Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

DNS Duplicate Record Script 1

Status
Not open for further replies.

djtech2k

MIS
Jul 24, 2003
1,097
US
I need something that will scan all A records on my DNS server and then identify which IP addresses are used more than once. I am trying to cleanup DNS so that there are NO multiple A-Records for a single IP and use CNAME's instead.

I can query the info from DNS fine, but I am thinking that I will need to use something like a dictionary to find the duplicates. Unfortunately, I am not well versed in the dictionary object. Here is what I have that I am using the query my DNS server:

Code:
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & _
        "\root\MicrosoftDNS")


Set colItems = objWMIService.ExecQuery("Select * from MicrosoftDNS_AType")

For Each objItem in colItems
If objItem.DomainName = "domain.net" Then
wscript.echo objItem.IPAddress & ";" & objItem.OwnerName
End If

Next

Any ideas?

 
You probably don't want to use a dictionary, because presumably you will be using the IPAddress as the key name. If there are duplicate IP Addresses then you will just end up overwriting the previous key.

You might want to try a multidimensional array instead, where each row stores an IP and the corresponding name. Then just take row 1 element 1, and compare it to element 1 for all of the other rows to see if the IP is listed more than once. Then repeat the process with row 2 element 1, etc.

The difference between dictionaries and multidimensional arrays can be difficult to get at first, but it will make sense eventually.

A dictionary looks like this:

Code:
Key          Value
192.168.0.1  Server1
192.168.0.2  Server2
192.168.0.3  Server3

The array looks like this:
Code:
Row          Element1          Element2
1            192.168.0.1       Server1
2            192.168.0.2       Server2
3            192.168.0.3       Server3

So when you go to check a value in an array, you specify the row and element number. When you check the value in a dictionary, you look it up by the key.

Does that make sense?
 
Thanks for the reply. Although I do understand your method in theory, I am not all that great with arrays outside of some simple ones.

I am doing some research, but the old array style is still a bit unclear to me.
 
I'm pretty sure that this will do it:

Code:
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & _
        "\root\MicrosoftDNS")

Dim arrARecords(1,1)

Set colItems = objWMIService.ExecQuery("Select * from MicrosoftDNS_AType")
i = 0

'   Puts all of the IP Address/Names pairs into the arrARecords array
For Each objItem in colItems
    If objItem.DomainName = "domain.net" Then
        arrARecords(i,0) = objItem.IPAddress
        arrARecords(i,1) = objItem.OwnerName
        Wscript.Echo objItem.IPAddress & ";" & objItem.OwnerName
        i = i + 1
        ReDim Preserve arrARecords(i,1)
    End If
Next

Wscript.Echo "Array loaded, beginning comparisons."

For x = 0 to UBound(arrARecords,1)
    strFirstIP = arrARecords(x,0)  'Sets the IP that we will start with
    Wscript.Echo "Looking for matches for " & strFirstIP
    For z = 0 to UBound(arrARecords,1)
        strCompareIP = arrARecords(z,0)  'Sets the IP that we will compare the first IP to 
        If x = z Then
        'This does nothing if x=z because if x=z we were be looking at the same record in 
        'the array and would therefore be expecting a match.
        Else
            'This is where we're actually looking for a matched/duplicate IP.
            If strFirstIP = strCompareIP Then
                Wscript.Echo "Duplicate records detected for " & strFirstIP & "with hosts:" _
                    & arrARecords(x,1) & " and " & arrArecords(z,1)
            Else
            End If
        End If
    Next
Next

But I haven't tested it yet. Does that make sense?
 
I just tried it and got an error on "ReDim Preserve arrARecords(i,1)"...."This array is fixed or temporarily locked."

I am reviewing, but thats the result thus far.
 
Only the last dimension of a non fixed array may be ReDim'ed Preserve.
A starting point:
Dim arrARecords
i = 0
ReDim arrARecords(1, i)
' Puts all of the IP Address/Names pairs into the arrARecords array
For Each objItem in colItems
If objItem.DomainName = "domain.net" Then
arrARecords(0,i) = objItem.IPAddress
arrARecords(1,i) = objItem.OwnerName
Wscript.Echo objItem.IPAddress & ";" & objItem.OwnerName
i = i + 1
ReDim Preserve arrARecords(1,i)
End If
Next

Hope This Helps, PH.
FAQ219-2884
FAQ181-2886
 
Ahh...I seem to learn something new every day.

So then if you switch the positions of the variables...
(x,0) should be (0,x), (x,1) should be (1,x), and the same goes for the z's as well.

Then the two instances of "UBound(arrARecords,1)" should be "UBound(arrARecords,2)" instead, since we're counting the second element.
 
Wow, you guys lost me. Can you guys tell me what I need to change to get this to work? As I said, the code that was originally posted produces the error I mentioned. What do I need to change?
 
This code replaces the previous code:

Code:
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & _
        "\root\MicrosoftDNS")

Dim arrARecords
i = 0
ReDim arrARecords(1, i)
'   Puts all of the IP Address/Names pairs into the arrARecords array
For Each objItem in colItems
  If objItem.DomainName = "domain.net" Then
    arrARecords(0,i) = objItem.IPAddress
    arrARecords(1,i) = objItem.OwnerName
    Wscript.Echo objItem.IPAddress & ";" & objItem.OwnerName
    i = i + 1
    ReDim Preserve arrARecords(1,i)
  End If
Next

Wscript.Echo "Array loaded, beginning comparisons."

For x = 0 to UBound(arrARecords,2)
    strFirstIP = arrARecords(0,x)  'Sets the IP that we will start with
    Wscript.Echo "Looking for matches for " & strFirstIP
    For z = 0 to UBound(arrARecords,2)
        strCompareIP = arrARecords(0,z)  'Sets the IP that we will compare the first IP to 
        If x = z Then
        'This does nothing if x=z because if x=z we were be looking at the same record in 
        'the array and would therefore be expecting a match.
        Else
            'This is where we're actually looking for a matched/duplicate IP.
            If strFirstIP = strCompareIP Then
                Wscript.Echo "Duplicate records detected for " & strFirstIP & "with hosts:" _
                    & arrARecords(1,x) & " and " & arrARecords(1,z)
            Else
            End If
        End If
    Next
Next
 
Another possible solution:

Code:
Option Explicit

Dim strComputer : strComputer = "."
Dim objDict : Set objDict = CreateObject("Scripting.Dictionary")
Dim objWMIService : Set objWMIService = GetObject("winmgmts:" _
    									& "{impersonationLevel=impersonate}!\\" & strComputer & _
        								"\root\MicrosoftDNS")

Dim colItems : Set colItems = objWMIService.ExecQuery("Select * from MicrosoftDNS_AType")
Dim objItem
For Each objItem in colItems
	If objItem.DomainName = "domain.net" Then
		If Not objDict.Exists(objItem.IPAddress) Then
			' add IP Address and record if it is not in our dictionary
			objDict.Add objItem.IPAddress, objItem.OwnerName
		Else 
			' if IP Address is already in dictionary update with additional record
			' with a | as a seperator
			objDict(objItem.IPAddress) = objDict(objItem.IPAddress) & "|" & objItem.OwnerName
		End If
	End If
Next

' loop through data in dictionary
Dim ipAddress, arrTemp, i 
For Each ipAddress In objDict.Keys
	' check for a | in the item which would indicate a duplicate
	If InStr(objDict(ipAddress), "|") Then
		WScript.Echo "Duplicate Records"
		WScript.Echo vbTab & "IPAddress: " & vbTab & ipAddress
		' create an array by using the Split function and the | as the seperator
		arrTemp = Split(objDict(ipAddress), "|")
		' loop through array
		For i = 0 To UBound(arrTemp)
			' echo out duplicates
			WScript.Echo vbTab & "Host: " &  vbTab & vbTab & arrTemp(i)
		Next
	Else
		' simply echo if there is no duplcate
		WScript.Echo "IPAddress: " & ipAddress & vbTab & " Host: " & objDict(ipAddress)
	End If
Next

--------------------------------------------------------------------------------
dm4ever
My philosophy: K.I.S.S - Keep It Simple Stupid
 
With either solution, what happens if there are more than 2 instances of the same IP?

As I read the code, it will only show the IP and its match, not multiple matches.
 
The example I posted will show something like this for duplicates:

Duplicate Records
IPAddress: XXX.XXX.XXX.XXX
Host: somehostname1
Host: somehostname2
Host: somehostname3

something like this for non-duplicates:
IPAddress: XXX.XXX.XXX.XXX Host: someotherhost

Maybe you can provide a clearer example of what type of output you're looking for.

--------------------------------------------------------------------------------
dm4ever
My philosophy: K.I.S.S - Keep It Simple Stupid
 
Sorry dm4ever, I was referring to the code that kmcferrin posted. I have not tried yours yet. I want to use it ASAP, but I am trying to wrap my brain around it so I can understand it and do it for myself next time. In both cases, it is something that I am not experienced with. Regex, arrays, and dictionaries are my weakest areas.

I will try your code first thing in the morning. I just need to report back any IP that is assigned to more than 1 A Record. Of course I need the names with the IP to find them. From what you said in your post, I think your output may be fine.

I will try and see. Like I said, I was trying to learn the arrays that kmcferrin posted up until this afternoon.

I will post back results.
 
I just tried it and it looks great! I am now looking to see if there is a part of the WMI class that will show me when/if each DNS record will be marked stale or pruned.
 
In my example, it will identify every match. So if there are more than two entries with the same IP address you will get a message with the IP address and conflicting names for each conflict.

Once you have found a conflict address, you'll still have to go into the DNS MMC snap-in to clear up the discrepancies, so if you sort by IP address then you should see all of the conflicts listed together.
 
Thanks. I am now trying to figure out how to tell which records are old and which are new. I know there's a timestamp but I do not know what format it is in.
 
Ok. I figured out how to convert the date....

DateAdd("h",objItem.TimeStamp,"1/1/1601 00:00:00 AM")

Now, should I convert the date before it gets entered into the dictionary or convert during the echo out from the dictionary? Also how do I add them to the dictionary? I tried adding it like this:

objDict.Add objItem.IPAddress, objItem.OwnerName, testdate

or

objDict.Add objItem.IPAddress, objItem.OwnerName, objItem.TimeStamp


But those do not work. For now, I am just doing something like:

objDict.Add objItem.IPAddress, objItem.OwnerName & " ; " & testdate

It is ugly, but it is working for now. How can I properly add the timestamp in there and pull it out of the dictionary in the right format?
 
With a dictionary you can only do
obDict.Add item1, item2

so since you want to add more data the example you posted:

objDict.Add objItem.IPAddress, objItem.OwnerName & " ; " & testdate

...should work. It is up to you if you want to enter the date in the proper format or convert it as you loop through it at the end. I'd format it as I add it to the dictionary.

--------------------------------------------------------------------------------
dm4ever
My philosophy: K.I.S.S - Keep It Simple Stupid
 
try this...

Code:
Option Explicit

Dim strComputer : strComputer = "."
Dim objDict : Set objDict = CreateObject("Scripting.Dictionary")
Dim objWMIService : Set objWMIService = GetObject("winmgmts:" _
    									& "{impersonationLevel=impersonate}!\\" & strComputer & _
        								"\root\MicrosoftDNS")

Dim colItems : Set colItems = objWMIService.ExecQuery("Select * from MicrosoftDNS_AType")
Dim objItem, timeStamp
For Each objItem in colItems
	' convert time stampt to std
	timeStamp = DateAdd("h", objItem.TimeStamp, "1/1/1601 00:00:00 AM")
	If objItem.DomainName = "testdomain.root" Then
		If Not objDict.Exists(objItem.IPAddress) Then
			' add IP Address, record, and timestamp if it is not in our dictionary
			objDict.Add objItem.IPAddress, objItem.OwnerName & ";" & timeStamp
		Else 
			' if IP Address is already in dictionary update with additional record
			' with a | as a seperator and timestamp
			objDict(objItem.IPAddress) = objDict(objItem.IPAddress) & "|" & objItem.OwnerName & ";" & timeStamp
		End If
	End If
Next

' loop through data in dictionary
Dim ipAddress, arrTemp, i, arrTemp2
For Each ipAddress In objDict.Keys
	' check for a | in the item which would indicate a duplicate
	If InStr(objDict(ipAddress), "|") Then
		WScript.Echo "IPAddress: " & ipAddress & " (Duplicates Found)"
		' create an array by using the Split function and the | as the seperator
		arrTemp = Split(objDict(ipAddress), "|")
		' loop through array
		For i = 0 To UBound(arrTemp)
			' echo out duplicates
			arrTemp2 = Split(arrTemp(i), ";")
			WScript.Echo vbTab & "Record: " & arrTemp2(0) & Space(40 - Len(arrTemp2(0))) & _
						         "TimeStamp: " & arrTemp2(1)
		Next
	Else
		arrTemp2 = Split(objDict(ipAddress), ";")
		' simply echo if there is no duplcate
		WScript.Echo "IPAddress: " & ipAddress & VbCrLf & vbTab & _
		 			 "Record: " & arrTemp2(0) & Space(40 - Len(arrTemp2(0))) & _
		 			 "TimeStamp: " & arrTemp2(1)
	End If
Next

--------------------------------------------------------------------------------
dm4ever
My philosophy: K.I.S.S - Keep It Simple Stupid
 
Oh, don't forget to change the domain name to yours if you try the example I posted above.

--------------------------------------------------------------------------------
dm4ever
My philosophy: K.I.S.S - Keep It Simple Stupid
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top