Link to home
Start Free TrialLog in
Avatar of Who Dat
Who DatFlag for United States of America

asked on

Update Preferred DNS throughout Domain

Have four DNS servers that are configured for TCP/IP.  About 6 months ago one of these servers for whatever reason, had an IP change.  Now throughout the domain, servers and workstation still maintain the incorrect DNS entry for this server, which is configured as the First preferred DNS entry.  

is there a way I can scan the network and determine all the DNS entries for the machines, most importantly servers.  And if there is a way to scan to verify whether the servers are updated correctly, we have about 300, is there a way to globally update all the servers?
Avatar of sk_raja_raja
sk_raja_raja

Probably you can update your dns servers address on all the workstations using group policy
Computer Configuration / Administrative Templates / Network / DNS Client / Primary DNS Suffix Group Policy setting and apply the GP
Avatar of Who Dat

ASKER

The problem with that is, it only allows for ONE DNS entry and there are FOUR
the probably you can use the DHCP server for this...thats the correct way to do it..When the DHCP leases the ip address it adds the DNS entry also.

Do you have a DHCP server?
Avatar of Who Dat

ASKER

yes, we have a DHCP server that has the up to date DNS info, but it doesn't appear to be pushing this info to the other servers
you have to make sure that all the workstation get the ip address from the DHCP server
Avatar of Who Dat

ASKER

well, the servers all have static IPs.  So they are manually configured w/the DNS information.  How can these entries be confirmed, as well as easily updated?
Attached is a VBScript WMI snippet that reports what it intends to change, and with a minor comment removal in the middle query section it also fixes all the DNS servers up for all the servers in the target OU or CN group.
You will want to run this as an admin for that group of servers, probably Domain Admin.
It also requires WMI access.

After you modify the user parameters at the top to what you need, run it and it will tell you what it intends to do - for 300 servers this will be pretty damn verbose. I think it works, so if you have WMI access to your servers there should be no problem - this step is optional.
I'd do a test run first if i were you, just for my peace of mind.

Once you decide to uncomment the update line, this line will also report the status of the operation: 0 is a good thing.
I'd suggest turning off the verbose "changed to ... from" for the real run, as it will be easier to read just the status codes.

If you want to do a test run first the easiest way is to set pingno to 30 or something, and CTRL-C out of it if you don't like what's going on.

If you don't have WMI access on your servers (tisk) there's also a fairly simple way of doing it with RemoteIT.au3 (google) and netsh, but it's a lot easier said than done.

On with my WMI script:
It will loop all the "Computer" objects in the target OU that answer to ping, loop all their network cards and all their respective DNS entries looking for your old DNS number, as set by the user strings upstairs

It stores the DNS for a network card (NIC) in two arrays - each array initially contains your old data.
The newdns array will get the old DNS number replaced by the new DNS number.
If it makes a replace in the array, the script sets an update flag which will be reset for the next NIC, which is then checked by the update conditions.
The update sequence will request the change, and return the NIC description text and the update's status.
The script then shows the old array and the new array.
Else, the update logic announces there will be no update on that NIC and moves on.

If ping fails on the server, the script simply announces it as unreachable "network error"
'PLEASE NOTE THIS SCRIPT IS NEUTERED BY DEFAULT BY A COMMENTED EDIT LINE IN THE QUERY CODE SECTION
 
'user parameter: old DNS Server IP address
oldDNS="192.12.33.2"
 
'user parameter: new DNS Server IP address
newDNS="192.13.3.3"
 
'user parameter - domain path
'example:  LDAPPath="LDAP://OU=Domain Controllers,dc=mydomain,dc=com"
'example2: LDAPPath="LDAP://CN=Computers,dc=mydomain,dc=co,dc=uk"
LDAPPath="LDAP://OU=Domain Controllers,dc=mydomain,dc=co,dc=uk"
 
'user parameter - number of pings before considering a host to be dead - should probably be at least 2 in a production script, but this should work fine
pingno=1
 
On Error Resume Next
 
Set objOU = GetObject(LDAPPath)
objOU.Filter = Array("Computer")
 
For Each objComputer in objOU
strComputer = objComputer.CN
 
Wscript.Echo strComputer
 
Set objShell = CreateObject("WScript.Shell")
 
strCommand = "ping -n " & pingno & " " & strComputer
 
Return = objShell.Run(strCommand,0,True)
 
If Return = 0 Then
 
' =====================================================================
 
' Insert your query code here
 
' =====================================================================
 
On Error Resume Next
 
Set objWMIService = GetObject( _
    "winmgmts:\\" & strComputer & "\root\cimv2")
Set colNetCards = objWMIService.ExecQuery _
    ("Select * From Win32_NetworkAdapterConfiguration " _ 
        & "Where IPEnabled = True")
 
For Each objNetCard in colNetCards
 
WillUpdateDNS=false
description=objNetCard.Description
 
 if (not isnull(objNetCard.DNSServerSearchOrder)) then
	arroldDNS = objNetCard.DNSServerSearchOrder
        arrnewDNS = arroldDNS
	For i=0 to UBound(arroldDNS)		
		if (arroldDNS(i) = oldDNS) then
			arrnewDNS(i) = newDNS
			WillUpdateDNS=true
		end if
	Next
 
	if (WillUpdateDNS) then
'NEUTERED		WScript.echo "dns updating on " &description & " status: " & objNetCard.setDNSServerSearchOrder(arrnewDNS)
		WScript.Echo "Updated to"
		for each newdns in arrnewdns
			WScript.Echo newdns
		next
 
		WScript.Echo "from DNS"
		for each olddns in arrolddns
			WScript.Echo olddns
		next
   	else 
		wscript.echo  "dns not updating on " &description
  	end if
  end if   
Next
 
WScript.Echo String(60,"=")
 
' =====================================================================
 
' End Query code
 
' =====================================================================
 
 
Else
Wscript.StdOut.WriteLine vbTab & "NETWORK ERROR"
End If
Next

Open in new window

Note that the script assumes independent DNS settings on each server, and works very hard at that.
If you have a fixed set of 4 DNS servers across the board it gets a lot safer/faster/simpler by just updating with a hand-made arrnewDNS = Array("xxx.xxx.xx.xxx","yyy.yyy.yyy.yyy
,"zzz.zzz.zzz.zzz","aaa.aaa.aaa.aaa")

But I'm silly like that sometimes. If you're still on throw up a comment about it and i'll mod the script for you if needed, but you're rather limited in time.
Avatar of Who Dat

ASKER

Does this WMI code produce an output file?
No, it just dumps everything on the console.

Run it from a cmd shell with "cscript wmifile.vbs"
if you want an output file to analyze use "cscript wmifile.vbs > testrun.log"
Avatar of Who Dat

ASKER

I created the snippet above and changed the OU values, etc. - ran as a VBS and got a pop up w/no data just an OK button.  What did I miss?
Avatar of Who Dat

ASKER

canonical name of the OU I can do a test run is:
us.ad.united.com/US Servers/Corp Servers

so in this section:
'user parameter - domain path
'example:  LDAPPath="LDAP://OU=Domain Controllers,dc=mydomain,dc=com"
'example2: LDAPPath="LDAP://CN=Computers,dc=mydomain,dc=co,dc=uk"
LDAPPath="LDAP://OU=Domain Controllers,dc=mydomain,dc=co,dc=uk"

I put
LDAPPath="LDAP://OU=Corp Servers,dc=us.ad.united,dc=com"
Which I'm sure is COMPLETELY wrong
This should be ok, assuming "corp servers" is of type OU, and the rest are subdomains - just split the domains with a dc for each :)

LDAPPath="LDAP://OU=Corp Servers,dc=us,dc=ad,dc=united,dc=com"

The reason you got a blank popup is that it wasn't finding the CN.
I neglected to mention the "run it in a command line with "cscript scriptfile.vbs" " thing initially, but don't miss that - or it will give you all the info in popups - a LOT of popups.
Oops, i just re-read your full post.
Two OUs, and THEN dc=us
Apologies, it's getting horribly late here.

LDAPPath="LDAP://OU=Corp Servers,OU=US Servers,dc=us,dc=ad,dc=united,dc=com"
Avatar of Who Dat

ASKER

ok, so I made the changes and ran from CMD, but I'm receiving pop up after pop up

One pop up said it performed the update; I thought it was supposed to produce output of what it would update before updating
It doesn't actually update until you uncomment the neutered line, but the rest looks nearly the same
You are getting popups because you probably didnt call it with cscript in front of the file name
Im sorry but i need to call it a night
Clarify in 6 hrs unless someone finds you a solution quicker
Avatar of Who Dat

ASKER

I didn't run the cmd with the csript - still playing around with it.  Have an output log that has a good majority of "NETWORK ERROR" entries.
ASKER CERTIFIED SOLUTION
Avatar of sciphre
sciphre
Flag of Romania image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Here's a small script to check WMI functionality.
Taken from http://msdn.microsoft.com/en-us/library/aa394595(VS.85).aspx

It will show all IP addresses for all interfaces that have IP enabled on the target computer.
'the commented out strcomputer addresses the local host
'strComputer = "."
strComputer = "myserverhostname"
 
Set objWMIService = GetObject( _
    "winmgmts:\\" & strComputer & "\root\cimv2")
Set IPConfigSet = objWMIService.ExecQuery _
    ("Select IPAddress from Win32_NetworkAdapterConfiguration" _
        & " where IPEnabled=TRUE")
 
For Each IPConfig in IPConfigSet
    If Not IsNull(IPConfig.IPAddress) Then 
        For i=LBound(IPConfig.IPAddress) _
        to UBound(IPConfig.IPAddress)
            WScript.Echo IPConfig.IPAddress(i)
        Next
    End If
Next

Open in new window

Avatar of Who Dat

ASKER

excellent! I'll work on this today and keep you posted.
Avatar of Who Dat

ASKER

ok, so the second set of code you sent:
'user parameter: old DNS Server IP address
oldDNS="192.12.3.2"
 
'user parameter: new DNS Server IP address
newDNS="192.13.3.3"

When I run it, it is not outputting the name of the servers that needs changes, only the ones that don't. I think the code is fantastic, but can you change to include the name of the server with the output file?  For example, the output file has hundreds of entries that just have:
============================================================
Would update DNS set
from DNS: 10.1.9.9 to: 10.6.9.19
============================================================

but the ones that don't need a change say
============================================================
dns update not needed on server USPRODUCTION NIC HP NC7771 Gigabit Server Adapter
============================================================
Avatar of Who Dat

ASKER

alright, I figured the &strComputer string out...

can you explain this in more detail?
If you have a fixed set of 4 DNS servers across the board it gets a lot safer/faster/simpler by just updating with a hand-made arrnewDNS = Array("xxx.xxx.xx.xxx","yyy.yyy.yyy.yyy
,"zzz.zzz.zzz.zzz","aaa.aaa.aaa.aaa")
OOps, the initial version had the server name on top and I removed it to clean up the vertical clutter.
I've added it to the actual modify lines, and the ones that don't modify, but the dry run verbose doesn't show it.

Here, how's this:
'user parameter: old DNS Server IP address
oldDNS="192.12.3.2"
 
'user parameter: new DNS Server IP address
newDNS="192.13.3.3"
 
'user parameter - domain path
'example:  LDAPPath="LDAP://OU=Domain Controllers,dc=mydomain,dc=com"
'example2: LDAPPath="LDAP://CN=Computers,dc=mydomain,dc=co,dc=uk"
LDAPPath="LDAP://OU=Corp Servers,OU=US Servers,dc=us,dc=ad,dc=united,dc=com"
 
'user parameter - number of pings before considering a host to be dead - should probably be at least 2 in a production script, but this should work fine
pingno=1
 
'user parameter - TRUE:Run without changing anything, and be very verbose about changes. FALSE:the script replaces DNS servers on affected network cards, reports the card name and the exit code of the change operation.
DRYRUN=TRUE
 
On Error Resume Next
 
Set objOU = GetObject(LDAPPath)
objOU.Filter = Array("Computer")
 
For Each objComputer in objOU
strComputer = objComputer.CN
 
Set objShell = CreateObject("WScript.Shell")
 
strCommand = "ping -n " & pingno & " " & strComputer
 
Return = objShell.Run(strCommand,0,True)
 
If Return = 0 Then
 
' =====================================================================
 
' Insert your query code here
 
' =====================================================================
 
On Error Resume Next
 
Set objWMIService = GetObject( _
    "winmgmts:\\" & strComputer & "\root\cimv2")
Set colNetCards = objWMIService.ExecQuery _
    ("Select * From Win32_NetworkAdapterConfiguration " _ 
        & "Where IPEnabled = True")
 
For Each objNetCard in colNetCards
 
WillUpdateDNS=false
description=objNetCard.Description
 
 if (not isnull(objNetCard.DNSServerSearchOrder)) then
        arroldDNS = objNetCard.DNSServerSearchOrder
        arrnewDNS = arroldDNS
        For i=0 to UBound(arroldDNS)            
                if (arroldDNS(i) = oldDNS) then
                        arrnewDNS(i) = newDNS
                        WillUpdateDNS=true
                end if
        Next
 
        if (WillUpdateDNS) then
           if (not DRYRUN) then 
                WScript.echo "dns updating" & " status: " &strComputer &" "& objNetCard.setDNSServerSearchOrder(arrnewDNS) & " " & description
            else
                WScript.Echo "Would update DNS set for " &strComputer
                for i=0 to UBound(arrnewdns)
                        WScript.Echo "from DNS: " &arroldDNS(i) &" to: " &arrnewdns(i) 
                next
           end if
        else 
                wscript.echo  "dns update not needed on server " &strComputer &" NIC " &description
        end if
  end if   
Next
 
WScript.Echo String(60,"=")
 
' =====================================================================
 
' End Query code
 
' =====================================================================
 
 
Else
Wscript.StdOut.WriteLine vbTab & "NETWORK ERROR"
End If
Next

Open in new window

Well, if you look at my code, it picks up the target's DNS servers array from WMI, then loops through it and replaces matches to the old DNS one by one.

If you knew that none of the machines have specific, custom DNS needs you could completely skip this "edit" step and just replace the whole array directly, therefore sparing you an interrogation and a couple of loops.

Not worth the trouble in this phase - it would have been much simpler to code than the current solution, if done from the beginning.
Avatar of Who Dat

ASKER

ok so I'm beginning to think all the servers are not listed in AD - how can I change the LDAP code to pull from a text file with all the server names?
Well, you'd need to replace the LDAP object with an FSO object.
Using this as a quick reference: http://www.itworld.com/nl/win_this_wk/04282003/

Also note that the non-Domain servers may be Linux-based, in which case WMI simply won't work.
You'll need to do that via SSH, which is easy, but a different question.

Note that the servers.txt file needs to be in the same folder. The lines are CN or FQDN, i'd recommend fqdn if they're not on the same domain.

Also note that the last line in servers.txt is empty - not sure why this is important but it locks up otherwise.

Have a shot:
'user parameter: old DNS Server IP address
oldDNS="192.12.3.2"
 
'user parameter: new DNS Server IP address
newDNS="192.13.3.3"
 
'user parameter - domain path
'example:  LDAPPath="LDAP://OU=Domain Controllers,dc=mydomain,dc=com"
'example2: LDAPPath="LDAP://CN=Computers,dc=mydomain,dc=co,dc=uk"
'LDAPPath="LDAP://OU=Corp Servers,OU=US 'Servers,dc=us,dc=ad,dc=united,dc=com"
 
'user parameter - number of pings before considering a host to be dead - should probably be at least 2 in a production script, but this 
 
should work fine
pingno=1
 
'user parameter - TRUE:Run without changing anything, and be very verbose about changes. FALSE:the script replaces DNS servers on affected 
 
network cards, reports the card name and the exit code of the change operation.
DRYRUN=TRUE
 
On Error Resume Next
 
'Set objOU = GetObject(LDAPPath)
'objOU.Filter = Array("Computer")
 
'For Each objComputer in objOU
'strComputer = objComputer.CN
 
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile("servers.txt",1)
Do Until objTextFile.AtEndOfStream
strComputer = objTextFile.Readline
 
Set objShell = CreateObject("WScript.Shell")
 
strCommand = "ping -n " & pingno & " " & strComputer
 
Return = objShell.Run(strCommand,0,True)
 
If Return = 0 Then
 
' =====================================================================
 
' Insert your query code here
 
' =====================================================================
 
On Error Resume Next
 
Set objWMIService = GetObject( _
    "winmgmts:\\" & strComputer & "\root\cimv2")
Set colNetCards = objWMIService.ExecQuery _
    ("Select * From Win32_NetworkAdapterConfiguration " _ 
        & "Where IPEnabled = True")
 
For Each objNetCard in colNetCards
 
WillUpdateDNS=false
description=objNetCard.Description
 
 if (not isnull(objNetCard.DNSServerSearchOrder)) then
        arroldDNS = objNetCard.DNSServerSearchOrder
        arrnewDNS = arroldDNS
        For i=0 to UBound(arroldDNS)            
                if (arroldDNS(i) = oldDNS) then
                        arrnewDNS(i) = newDNS
                        WillUpdateDNS=true
                end if
        Next
 
        if (WillUpdateDNS) then
           if (not DRYRUN) then 
                WScript.echo "dns updating" & " status: " &strComputer &" "& objNetCard.setDNSServerSearchOrder(arrnewDNS) & " " & 
 
description
            else
                WScript.Echo "Would update DNS set for " &strComputer
                for i=0 to UBound(arrnewdns)
                        WScript.Echo "from DNS: " &arroldDNS(i) &" to: " &arrnewdns(i) 
                next
           end if
        else 
                wscript.echo  "dns update not needed on server " &strComputer &" NIC " &description
        end if
  end if   
Next
 
WScript.Echo String(60,"=")
 
' =====================================================================
 
' End Query code
 
' =====================================================================
 
 
Else
Wscript.StdOut.WriteLine vbTab & "NETWORK ERROR"
End If
Loop

Open in new window

servers.txt
Avatar of Who Dat

ASKER

ok, I get his error when I try to run your updated script:
C:\dnscheck.vbs(14, 13) Microsoft VBScript compilation
 error: Expected end of statement
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Who Dat

ASKER

ok, so I started the script about 20 mins ago and it only has one line in an output file. I do have the extra line in servers.txt - what do you think it's doing? I have an output file that only has one line so far
Well, to non-domain servers i guess you're bound to have issues with credentials and firewall, also some of them may not even be running windows.

The time out for WMI takes forever.

I don't believe i can help you much from here on - doing it on the domain is one thing, "in the wild" is another. You're unlikely to be able to edit them as one.

Sorry about not being able to fix all of the servers - I hope the ones on the domain went smooth enough.
Avatar of Who Dat

ASKER

your coding has been wonderful.  the last code is still running and the output file size is increasing - so that's definitely a good sign...

thanks for the input
Avatar of Who Dat

ASKER

sciphre, outstanding input and direction! hope to run into you again!
Thank you for having interesting problems :)
I'll keep monitoring this in case you have any more issues - but the off-domain servers have very low chances of working I'm afraid.
Avatar of Who Dat

ASKER

sciphre, you may have already said but I'll ask again...
when it comes time to update the incorrect DNS entries, what's the quickest way, rather than one by one...
if you say there's an easy way, I'll post another question for you to answer
I don't understand the question, but it sounds like you just need to disable DRYRUN mode and let the script fix everything.
If you meant for the off domain ones, i don't know a fast way.
You could make a small batch file that uses   netsh, but you would still need to log on remotely on each to run it, as you can't predict the management settings on them.
I'll rephrase that:
-The last script that still uses LDAP is blazing fast and will update all your domain machines in a jiffy, as long as you've opened up WMI on them, which I gather you have. This is a solution i can stand behind and i'll help you through with it until it works.

-The server list script will often run into machines which have firewalls on them. The time out for this is huge and if there are any such machines in the list it will run dog slow. This is a solution i cannot support due to the inherent complexity of a non-domain environment.
- I may be able to amend the server list script into using alternate credentials for each server, but you'd still have firewall problems with it.

Offtopic:
The off-domain servers should really  have some sort of central mechanism for administration left on them by whoever managed them initially, but you'll need to figure out what it is or you will end up in the madhouse.
Avatar of Who Dat

ASKER

understood - I'll disable the dryrun and keep you posted. thanks
Avatar of Who Dat

ASKER

Wow! setting the DRYRUN to FALSE has absolutely no effect on the update.  I expected the servers to flicker or something but nothing. OUTSTANDING!
Actually it changes the verbosity level a bit, makes it easier to read since you're already aware of what it's gonna do :)
I do hope it worked.
Avatar of Who Dat

ASKER

sciphre,
I forgot...is there a way to edit the code to also update the WINS entries?
Should be trivial, but I can't do it today.
Here's a reference, it's pretty much search & replace, you should be able to figure it out.

http://msdn.microsoft.com/en-us/library/aa393624(VS.85).aspx

Changes:
- SetDNSSearchOrder becomes SetWINSServer
- Since SetDNSSearchOrder takes an Array as a parameter, and SetWINSServer takes two strings, you'll need two string variables instead of an array.
- On a similar note,  string WINSPrimaryServer,  string WINSSecondaryServer will show you the servers, this will also need some modification.

If you're not a programmer at all, I can probably help in some 20 hours. Would really appreciate it if you made a new question though - and if you're lucky someone else might get to it earlier, since the hard part is already done .
Avatar of Who Dat

ASKER

I can't even pretend to be a programmer; I tried but just can't translate :)

here's a new question:
https://www.experts-exchange.com/questions/23795743/Update-WINS-entries-throughout-domain.html