Typically, internal DNS entries for websites must be different than the external addresses due to NAT issues. If your organization has a lot of web sites that exist on either a single server or a set of identical servers behind a load balancer, it’s best practice to have all DNS entries be CNAME records to either that particular server’s DNS entry or the entry for a server farm’s load balancer. Recently I was involved in a mass server migration where actual IPs were used throughout a Windows DNS server. The following is a Power Shell script designed to rename DNS records in mass on an Active Directory Domain Controller.

First, I’d like to thank Ansgar Wiechers for his help on this problem and well as Chris Dent’s very helpful powershell/dns post. In the following example, machines were being moved from the 192.168 subnet into the 10.19 subnet. This script will need to be modified for your needs obviously and it comes with no guarantees or warranties what so ever, so you run it entirely at your own risk. This was a very quick script written during a high stress server move, and we still had problems that may or may not have been related to this script afterwords.

I’ve just posted it up here because I couldn’t find any good examples of this anywhere. I knew someone else, somewhere down the line, would run into a very similar situation. On a side note, if this particular organization was using BIND or another file based DNS server instead of Windows / Active Directory, this entire operation could have been done with a series of simple search and replaces.

#The name of your Active Directory / DNS server $dnsServer = "myExampleAD" $scope = New-Object Management.ManagementScope("\\$dnsServer\root\MicrosoftDNS") $path = New-Object Management.ManagementPath("MicrosoftDNS_Zone") $options = New-Object Management.ObjectGetOptions($Null,[System.TimeSpan]::MaxValue, $True) $ZoneClass= New-Object Management.ManagementClass($scope,$path,$options) $Zones = Get-WMIObject -Computer $dnsServer -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_Zone" foreach($Z in $Zones) { if (( $Z | Select-Object -expand Reverse) -ne "True") { $domain = $Z | Select-Object Name $dname = $domain.Name dnscmd /EnumRecords $domain.Name `@ /type A | % { $name = $_.split(" ")[0] $ip = $_.split("`t")[-1] #The IP records for our web servers. These will need to be changed # depending on your situation if (($ip.Contains("192.168.0.14")) -or ($ip.Contains("192.168.0.80")) -or ($ip.Contains("192.168.0.220")) -or ($ip.Contains("192.168.0.229")) -or ($ip.Contains("192.168.0.230")) -or ($ip.Contains("192.168.0.241")) -or ($ip.Contains("192.168.0.16")) -or ($ip.Contains("192.168.0.140")) -or ($ip.Contains("192.168.0.221")) -or ($ip.Contains("192.168.0.224")) -or ($ip.Contains("192.168.0.225")) -or ($ip.Contains("192.168.0.226")) -or ($ip.Contains("192.168.0.227")) -or ($ip.Contains("192.168.0.233")) -or ($ip.Contains("192.168.0.234")) -or ($ip.Contains("192.168.0.235")) ) { #Here we see the ranges we are moving from: 192.168 to 10.19. $ip = $_.split("`t")[-1] $new = $_.split("`t")[-1] -replace "192.168", "10.19" echo "dnscmd $dnsServer /recorddelete $dname $name A" # you can uncomment the /f switch below if you're brave. Otherwise, you'll be prompted for each delete dnscmd $dnsServer /recorddelete $dname $name A # /f echo "dnscmd $dnsServer /recordadd $dname $name A $new" dnscmd $dnsServer /recordadd $dname $name A $new } } } }

Obviously this was very quick and dirty and I wanted to minimize the changes being made. A better solution would be to create CNAME records for each of those A records instead, pointing to the correct DNS entry for each IP address listed. However, this example should be a decent starting point for similar types of mass changes on Windows based DNS systems.