Skip to content

Dns Backups In Powershell

Tags: powershell, windows_dns, backups


DNS backups are a bit complicated, you need to backup and restore each zone individually with files that are in a static location in System32. Most sources I found used dnscmd which is too DOS for me, we need to PowerShell it up. I ended up finding that Add-DnsServerPrimaryZone would work for my needs despite what some sources said about there being no PowerShell way to do this.

Code

Backup

Terminal window
$log = 'C:\dns_backup.log'
Start-Transcript $log
#Requires -RunAsAdministrator
# --- Initializations --- #
If (Test-Path '.\send-mail\send-mail.ps1') {
. .\send-mail\send-mail.ps1
} Else {
Throw "send-mail is missing"
}
# --- Declarations --- #
#user vars, change these
$backupLocation = "\\dsk7\backups-smb\dns\"
$archive = "C:\$(Get-Date -UFormat %Y-%m-%d)-$env:COMPUTERNAME.dns.zip"
#system vars, you likely don't change these
$dnsRoot = 'C:\Windows\System32\dns\'
$primarys = Get-DnsServerZone | Where-Object { $_.ZoneType -eq 'Primary' }
# use an array to catch bad things and put it in our email
$failureArray = @()
$result = "success"
# --- Functions --- #
Function mail {
# stop must be here so that the file can be unlocked whenever we want to mail
Stop-Transcript
If ($failureArray.Count -gt 0) {
$result = 'failure'
} Else {
$result = 'success'
}
send-mail -to 'user@contoso.com' -subject "DNS Backup on $env:COMPUTERNAME $result" -body "Failures: $failureArray" -attachment $log
}
# --- Execution --- #
ForEach ($z in $primarys) {
$zone = $z.ZoneName
# auto created zones fail to export
If ($z.IsAutoCreated -eq $false -And $z.ZoneName -notLike "*arpa") {
Write-Host "Zone $zone" -ForegroundColor Green
$file = "$zone.dns.bak"
Write-Host "Exporting $zone to $file" -ForegroundColor Green
Try {
Export-DnsServerZone -Name $zone -FileName $file
} Catch {
Write-Warning "Failed to backup $zone"
$failureArray += $zone
Write-Host $_
}
$backupFile = $dnsRoot + $file
}
}
# zip-em and move-em
$zipFiles = "$dnsRoot\*.dns.bak"
Write-Host "Compressing archive $archive" -ForegroundColor Green
Compress-Archive -Path $zipFiles -DestinationPath $archive
Write-Host "Moving $archive to $backupLocation" -ForegroundColor Green
Try {
Move-Item -Path $archive -Destination $backupLocation
} Catch {
$failureArray += "move failure"
Write-Warning "move failure"
Write-Host $_
}
Try {
Remove-Item -Path "$dnsRoot\*.dns.bak" -Recurse
} Catch {
Write-Warning "failed to remove backup dir"
$failureArray += 'backup dir failed to remove'
Write-Host $_
}
# --- Ending Tasks --- #
mail
Note

This script utilizes my email script submodule.

Recovery

Terminal window
Start-Transcript 'C:\dns_recovery.log'
#Requires -RunAsAdministrator
Function dns_recovery {
param (
[Parameter(Mandatory=$True)]
[Object]$archive
)
# this cannot be changed, the commands will only load files from this dir
$dnsRoot = "C:\Windows\System32\dns"
If (!(Test-Path $archive)) {
Throw "$archive does not exist, check the path and try again"
}
Write-Host "Expanding $archive at $dnsRoot" -ForegroundColor Green
Expand-Archive -Path $archive -DestinationPath $dnsRoot
$allFiles = Get-ChildItem $dnsRoot
$backupFiles = $allFiles | Where {$_.Name -Like "*.dns.bak"}
ForEach ($file in $backupFiles) {
$zone = $file.Name.Replace('.dns.bak','')
Write-Host "Loading $zone from $file..." -ForegroundColor Green
Try {
Add-DnsServerPrimaryZone -ZoneName $zone -ZoneFile $file.Name -LoadExisting
} Catch {
Write-Warning "Failed to restore $zone"
}
}
Write-Host "Removing files from $dnsRoot"
Remove-Item -Path "$dnsRoot\*.dns.bak"
}
dns_recovery
Stop-Transcript

Notes

  • The exported files are plaintext
  • When exporting you can only specify a file name not location. The files can only go to C:\Windows\System32\dns and must be moved from there.

Updates: 2022-04-22: Added a check for arpa specifically as it was an issue on my home DNS server.

References

Another basic script

An overview on the cmdlets and commands

Using PowerShell

Docs on DNSServer Module