DNS Zone Copy and Merge with PowerShell

Have you ever wanted to roll up all of your reverse zones into a "big 10" super zone? Do you need to copy DNS zones between environments and preserve the record aging? Today's post is for you.

OneNoteAuthor’s note: While flying home on a Friday night this blog post was mostly composed on my Windows Phone in OneNote, synced to OneDrive, continued from my laptop, pasted into Windows Live Writer, and then posted to TechNet. I love OneNote for being productive on-the-go!

Looking Back

Have you ever reviewed the first PowerShell scripts you wrote? Yeah. It's painful. The only difference is that mine are public here on TechNet. I've learned so much since I started blogging about PowerShell four years ago. People are still finding and using some of my first scripts.

For the last year I have been wanting to update my DNS zone consolidation script. I posted this one in September of 2010. Recently I had a customer who needed this solution, and it gave me the perfect chance to improve it.

NOTE: Today's article references many DNS terms and concepts. If these are unfamiliar to you I would recommend reading up on DNS using the links on this page. https://aka.ms/AD101

Simple Zone Copies

Traditionally if you want to copy a DNS zone to another environment you just create a secondary copy of the zone at the destination, pull the records from the primary, then promote the secondary copy to a primary. The only issue here is that secondary zones lose the time stamping, and that may be a deal breaker for some folks.

Another way is to do a zone export with DNSCMD first. Then you copy that to the destination server, create a new zone, and point it to the export file. Unfortunately when you create a new zone on Windows DNS it defaults to no aging. When you go back to the new zone to enable aging after it is created the timestamps were lost during the import to the new zone lacking aging.

These comments are based on my own experience. If you know other ways to achieve the goal of copying a DNS zone with timestamps in tact please tell us in the comments below.

Scripting DNS

My original script used WMI exclusively, limitations and all. I've used DNSCMD with other scripting solutions, but it is now deprecated in Windows Server 2012. It still works, but it is not guaranteed to be there in the future.  Check out this output at the bottom of the help for DNSCMD:

 PS C:\> dnscmd /?

Usage: DnsCmd <servername> <command> [<command parameters>]
In future versions of Windows, Microsoft might remove dnscmd.exe.

If you currently use dnscmd.exe to configure and manage the DNS server,
Microsoft recommends that you transition to Windows PowerShell.

To view a list of commands for DNS server management, type
"Get-Command -Module DnsServer" at the Windows PowerShell prompt. Additional
information about Windows PowerShell commands for DNS is available at

PS C:\>

NOTE: For a handy guide to moving your DNSCMD commands to PowerShell see this link.

With Windows Server 2012 we released a ton of great cmdlets to script DNS. As luck would have it this particular customer was still using Windows Server 2003 R2 for all of their domain controllers (in the year 2014). Fortunately this was not a problem. They set up a Windows Server 2012 tools server in a dev forest, and we ran all the new cmdlets from there. So yes, the new DNS cmdlets work well even when targeting legacy operating systems.

Problem Revisited

Over the years many AD shops have treated reverse DNS as a step-child. We touch it only when someone complains that the crusty old app using reverse DNS is broken again. And then often the folks implementing the fix don't have a good grasp of the way DNS works. This leads to a hodgepodge of reverse zones that are very outdated and very cumbersome to administer.  Nine times out of ten the nameserver records for all those zones never get updated when domain controllers come and go.

This particular customer had nearly 350 reverse zones. We consolidated them down to 5. Keep reading to find out how.

TIP: Active Directory itself has ZERO dependencies on reverse DNS.

Now you may be thinking... "Reverse zone consolidation is easy. Just delete all of them. Create one big 10.in-addr.arpa and let the clients reregister dynamically." In most cases that would work, except for two issues:

  • Some static reverse entries are there for a reason, and you cannot simply blow them away. Of course no one in the department knows which ones are important.
  • This customer had a critical business app that relied on reverse DNS. Yes, it was old. Yes, they knew it.

This being the case we needed to preserve all of the existing reverse DNS records.

This same scenario could apply to forward zones, but it is less common. You can use the same code to roll up separate subzones into a single parent zone.

At the same time this customer had not run scavenging for two years. The reverse zones were full of old data that did not need populated in the new, consolidated zones. We turned scavenging back on, but we didn't have time to wait for the first big pass of deletions.

In case you think I'm picking on this customer, then don't take this the wrong way. I've seen the same issues at many customers. I am calling out these examples, because they are real world. I'm guessing you are still reading, because you “know someone” with similar issues.

Out With The Old

My first script had a number of limitations:

  • WMI doesn't scale well in large DNS environments.
  • WMI methods cannot add a dynamic record, only static. (Both DNSCMD and PowerShell support dynamic record additions.)
  • I wrote the WMI query in the most inefficient way possible, slowing performance. That was before I knew “Filter left, format right.”

Time for a PowerShell make-over.

Two Possible Approaches

Recently a different customer came to me with an unusual request. They wanted to script building out reverse DNS zones based on data in the forward zones. I wrote a script to read all of the A and CNAME record data from the forward zones and then created new reverse zones where I populated new records. This scenario was a long story, but it was not a good solution for this week's customer.

The better approach was to copy all of the /16 and /24 reverse zones up into the top level /8 zones. Some people call these "super zones" or a "big 10". After the records were copied we would delete the old zones.

Quick Side Bar

Pay attention to the DNS zone storage of the reverse zones. Are they standard primary zones on a single DC? Which AD-integrated partitions are the zones stored in (Domain, DomainDNS, ForestDNS)? This affects where the zones are actually effective. Plan where you want to store the zones going forward (DomainDNS or ForestDNS).

Enter PowerShell

imageTo make this work we need to execute the following steps:

  • Enumerate all of the zones to be copied.
  • Create the new top level zones (10.in-addr.arpa, 192.in-addr.arpa, etc.) if they do not already exist. Don’t forget to turn on aging for the zone!
  • Remove any delegations to subzones in any existing top-level zones. These would cause the record additions to fail. Later I added this to the script.
  • Copy the records into the new top level zones, preserving dynamic timestamps.
  • Verify the records are accurate.
  • Allow time for replication of AD-integrated zones.
  • Delete the old zones.

I have done this with multiple customers. I always recommend working from a DC DNS server where no clients are pointing for name resolution. We create the new top-level zones as standard primary (text file based) first. Then when the zone consolidation looks good we turn them up to AD integrated and let them replicate out.

By default new records are static. In my code I check the source record to see if it has a timestamp. If not, then we add a static record. If it has a timestamp, then we use the -AgeRecord switch with the cmdlet. Here is the rub. You cannot copy the exact timestamp from the old record to the new one. Therefore any dynamic records will get a fresh timestamp. This may cause a hiccup in your scavenging, but it should not be a significant issue.

Since I knew many of the records in the source zone were already stale I added a -StaleDays parameter to my DNS zone copy function. Any dynamic record whose timestamp is older than this value will not be copied.

DNS Cmdlets

In this solution we use the following cmdlets from the PowerShell module DnsServer:

  • Get-DNSServer
  • Get-DNSServerZone
  • Add-DNSServerResourceRecord

We use these cmdlets to build new functions to help with finding and copying the zones. Note that these cmdlets are only available on Windows Server 2012 and above, or Windows 8.0 Remote Server Administration Tools (RSAT) and above.  All you need is a Windows Server 2012 tools server somewhere in your environment. Get a list of DNS cmdlets this way: Get-Command -Module DNSServer, DNSClient -or- use Show-Command and filter on the DNS modules.

My DNS PowerShell Functions

Copy-DNSServerZone will do exactly what it sounds like. It copies a single source zone from a source server to a destination zone on a destination server. The source and destination servers can be the same or different. Currently this function only handles A, CNAME, PTR, MX, and SRV records. Feel free to add other record types as needed. Note that we automatically exclude copying NS or SOA records, because those are unique to the destination server.

Copy-DNSZoneReverse is a calling function to automate enumerating all of the reverse zones in source/destination pairs for the consolidation. It will automatically find all the /16 and /24 reverse zones that need to be copied into the /8 zones and pass them to Copy-DNSServerZone. All you need to supply are the source and destination servers.

Remove-DNSZoneReverse will remove all DNS reverse zones except the top-level ones (10.in-addr.arpa, etc.). It is much faster than manually deleting a couple hundred reverse zones. Obviously be careful with this. Just to be safe my version forces you to confirm each zone deletion.

Points to plan for:

  • These function expect that you have already created the top-level destination zone(s).
  • This process does not account for zone security on “Secure Only” update zones.  Usually reverse zones allow non-secure updates, so this is likely not a factor for you. However, when adding records the function uses the –AllowUpdateAny switch just to be safe.
  • Before you remove the old zones allow time for replication to populate the new zones on all servers. You can monitor this by adding multiple DNS servers to your management console. You can hurry it along using REPADMIN or AD Sites and Services.
  • Schedule your change control for a maintenance window. Generally this process does not cause significant disruption when executed correctly. Do it after hours to be safe.
  • In the DNS console you can turn on advanced view (View, Advanced). This tells you the next time scavenging will run on a zone. (Zone, Properties, Aging, This zone can be scavenged after). It also shows the 0. , 127. , and 255. reverse zones. These are automatic, built in zones. Do not delete these. The Remove-DNSZoneReverse function excludes these automatically.
  • Be sure that you have a backup in case things go bad.  Just sayin’.

NOTE: I have included other handy DNS functions in the script download for this article.

Show me some code!

Using these custom PowerShell DNS functions you can now automate your DNS zone roll ups using commands like this:

 # Log all console output            
Start-Transcript .\ReverseDNS.txt            
# Dot source to import the DNS functions            
. .\DNSFunctions.ps1            
# Example: Copy a single zone            
Copy-DNSServerZone -SrcServer dc1.contoso.com -SrcZone "1.5.10.in-addr.arpa" `
    -DestServer dc1.contoso.com -DestZone "10.in-addr.arpa" `
    -StaleDays 21            
# Example: Roll up all reverse zones            
Copy-DNSZoneReverse -SrcServer dc1.contoso.com -DestServer dc2.contoso.com            
# Allow time for replication if needed            
# Verify that the consolidated zones look good            
# Troubleshoot any errors            
# Example: Remove all but the top-level reverse zones            
Remove-DNSZoneReverse -Server dc2.contoso.com            
# Save the log            

These are examples of how you can use the commands.  Don’t run it exactly like these samples. Using the steps highlighted above and this sample code you can create your own automated process. Remember to take a backup before you start and allow time for replication afterward.

Download this DNS function library at the TechNet Script Center .