Windows PowerShell DNS Backup Script

Summary

Several things suck about Microsoft's DNS implentation, but the top two for me have to be security and backups. I don't know how many times I've had to explain to a team that I was not going to give them access to the DNS MMC snap-in because it would mean dozens or hundreds of Deny ACLs on zones in that environment. But that's another post.

This post is about DNS backups. After experiencing the kind of event that causes one to review one's DNS backup plan, I found there wasn't a tidy way to back up AD-integrated zones like the options for AD, DHCP, and other infrastructure services. I started with a 36-line .bat file that required modification and an individual scheduled task for each zone that needed to be backed up. With the advent of the basic DNS cmdlets in Server 2008 R2, I moved on to an unholy combination of a PowerShell script that gathered zone info and called my old script in a loop. Not efficient, but it only needed one scheduled task.

The script below is a result of even more DNS cmdlets and functions being available in Windows Server 2012. Using them and the piping inherent in PowerShell, I was able to reduce the entire process to a 10-line script that can be dropped into any environment without modification and back up all AD-integrated primary zones on a server.


Script

 # Pulls an environment variable to find the server name, queries it for a list of zones, filters only the primary ones, removes the quotes from the exported .csv file, and saves it to the specified folder.
Get-DNSServerZone -ComputerName $env:computername | Where-Object{$_.ZoneType -eq "Primary"} | Select ZoneName | ConvertTo-CSV -NoTypeInformation | ForEach-Object {$_ -replace ‘"‘, ""} | Out-File "C:\DNSBackups\Exports\ZoneTemp.csv"

# Imports the zone list
$ZoneList = Get-Content "C:\DNSBackups\Exports\ZoneTemp.csv"

# Pulls the date variables in the appropriate formats
$Year = Get-date -Format yyyy
$Month = Get-Date -Format MM
$Day = Get-Date -Format dd

# Starts a loop for each line in the zone list
ForEach ($line in $ZoneList) {

# Exports the zone info with the desired naming scheme
Export-DNSServerZone -Name $line -FileName "${line}_$Year-$Month-$Day.txt"

# Moves the export file from the default location to the Exports folder
move "C:\Windows\System32\dns\${line}_$Year-$Month-$Day.txt" "C:\DNSBackups\Exports\${line}_$Year-$Month-$Day.txt"

}

# Removes all files in the Exports folder older than 7 days
forfiles /p "C:\DNSBackups\Exports" /d -7 /c "cmd /c del @file"

Requirements

  • This script must be set up and created on an active Microsoft DNS server. I don't know of a way to run it from a remote machine and natively have the imports be exported locally. You could run it via a remote session from another box, but considering the exports will stay on the DNS server itself without adding cross-network move commands, I don't see the value.
  • The host server must be at least Windows Server 2012. The Export-DNSServerZone cmdlet is not supported in Server 2008 R2.
  • You must set the appropriate security for the service account that runs the script. See the Deployment section below.

Deployment

  1. Create the following folders on the server where you'll be deploying this process
    1. C:\DNSBackups
    2. C:\DNSBackups\Exports
    3. C:\DNSBackups\Scripts
  2. Create a service account to run the process using your standard configuration. Grant it the following access:
    1. Membership in the DNSAdmins domain role group
    2. Membership in the Backup Operators domain role group
    3. NTFS Read access to C:\DNSBackups\Scripts
    4. NTFS Modify access to C:\DNSBackups\Exports
    5. NTFS Modify access to C:\Windows\system32\dns folder (you will receive a permissions denied error for a subfolder; that's OK)
  3. Copy the script above to BackupDNS.ps1 under C:\DNSBackups\Scripts.
  4. Create a scheduled task that calls the BackupDNS.ps1 with the interval of your choosing (the file naming is based on once a day) and runs under the service account you created.

Notes

  • This script literally gets all the primary zones on the server, including reverse zones. I suppose you could filter those out somehow, but depending on your environment/applications, the reverse data could be as important as the forward.
  • I left the ZoneTemp.csv file in place for troubleshooting purposes. It overwrites every time, so there's no technical need to remove it after every run.
  • No script customization should be necessary as long as you follow the deployment steps above. The script should pull all the variables it needs.
  • As of the writing of this post, there is no way to customize the export path for the zone files. That is why the move commands are necessary.
  • If you want/need to change the path for the Scripts or Exports folders, make sure to modify them in all the necessary locations in the script.

Known Issues

  • To establish a scheduled task using stored credentials on the target server, the following setting must be defined by GPO or allowed to maintain the default OS setting:
    • Location: Computer Configuration/Policies/Windows Settings/Security Settings/Local Policies/Security Options
    • Key: Network access: Do not allow storage of passwords and credentials for network authentication
    • Setting: Disabled
  • If Backup Operators has been removed from the following key, either it or the DNS backups service account must be added:
    • Location: Computer Configuration/Policies/Windows Settings/Security Settings/Local Policies/User Rights Assignment
    • Key: Log on as a batch job
  • If ACLs for the default DNSAdmins group has been removed or modified on either the server object or the zones, you may have to revert to default or manually add the ACLs back to allow the account the access it needs. To clean up/replace ACL entries for AD-integrated zones at the top level, use DOMAINROOT/System/MicrosoftDNS.

Comments

  1. Thank you for sharing this! I was setting out to do exactly what this script already does. You saved me quite a bit of time.






    ReplyDelete

Post a Comment