At its core, DNS is a system that eliminates the complexity of accessing services via IP addresses by allowing users to connect effortlessly using domain names.
- It facilitates domain name resolution and management.
- Directs queries to the appropriate destinations.
DNS zones and reverse lookup zones are crucial components of a robust and secure network infrastructure.
In this article, I will share several scripts that you can use as needed. These scripts are designed to address the following requirements:
- Exporting the names of all zones in DNS
- Extracting all records associated with the zones listed in the exported file
- Exporting all records from a specific zone of your choice
- Restoring a deleted zone if necessary
- Add Reverse Lookup Zones
Exporting All Zones in DNS
# Output file path
$outputFile = "C:\Script\DNSOperation\DNSZoneNameExport.csv"
try {
# Fetching DNS zones
$zones = Get-DnsServerZone
if ($zones) {
# Preparing data for export
$zoneData = $zones | Select-Object -Property ZoneName
# Exporting to CSV
$zoneData | Export-Csv -Path $outputFile -NoTypeInformation -Encoding UTF8
Write-Host "DNS zones have been successfully exported to $outputFile" -ForegroundColor Green
} else {
Write-Host "No DNS zones found." -ForegroundColor Yellow
}
} catch {
Write-Host "An error occurred while fetching DNS zones: $_" -ForegroundColor Red
}
Exporting All Zones in Records
# Zones CSV Path
$zonesFile = "C:\Script\DNSOperation\DNSZoneNameExport.csv"
$zones = Import-Csv -Path $zonesFile
foreach ($zone in $zones) {
$zoneName = $zone.ZoneName
$OutputFile = "C:\Script\DNSOperation\$zoneName.csv"
$Report = [System.Collections.Generic.List[Object]]::new()
$zoneInfo = Get-DnsServerResourceRecord -ZoneName $zoneName
foreach ($info in $zoneInfo) {
$timestamp = if ($info.Timestamp) { $info.Timestamp } else { "static" }
$timetolive = $info.TimeToLive.TotalSeconds
$recordData = switch ($info.RecordType) {
'A' { $info.RecordData.IPv4Address }
'CNAME' { $info.RecordData.HostnameAlias }
'NS' { $info.RecordData.NameServer }
'SOA' { "[$($info.RecordData.SerialNumber)] $($info.RecordData.PrimaryServer), $($info.RecordData.ResponsiblePerson)" }
'SRV' { $info.RecordData.DomainName }
'PTR' { $info.RecordData.PtrDomainName }
'MX' { $info.RecordData.MailExchange }
'AAAA' { $info.RecordData.IPv6Address }
'TXT' { $info.RecordData.DescriptiveText }
default { $null }
}
$ReportLine = [PSCustomObject]@{
Name = $zoneName
Hostname = $info.Hostname
Type = $info.RecordType
Data = $recordData
Timestamp = $timestamp
TimeToLive = $timetolive
}
$Report.Add($ReportLine)
}
$Report | Export-Csv -Path $OutputFile -NoTypeInformation -Encoding utf8
Write-Host "DNS records for $zoneName exported successfully." -ForegroundColor Green
}
Exporting Specific Zone in Records
try {
$Report = [System.Collections.Generic.List[Object]]::new()
$zoneName = "yusufustundag.com"
# Fetching zone information
try {
$zoneInfo = Get-DnsServerResourceRecord -ZoneName $zoneName -ErrorAction Stop
} catch {
Write-Host "Error: Unable to fetch zone information. Zone name: $zoneName" -ForegroundColor Red
throw $_
}
# Processing records
foreach ($info in $zoneInfo) {
try {
$timestamp = if ($info.Timestamp) { $info.Timestamp } else { "static" }
$timetolive = if ($info.TimeToLive) { $info.TimeToLive.TotalSeconds } else { "N/A" }
$recordData = switch ($info.RecordType) {
'A' { if ($info.RecordData.IPv4Address) { $info.RecordData.IPv4Address } else { "No IP" } }
'CNAME' { if ($info.RecordData.HostnameAlias) { $info.RecordData.HostnameAlias } else { "No Alias" } }
'NS' { if ($info.RecordData.NameServer) { $info.RecordData.NameServer } else { "No NameServer" } }
'SOA' { if ($info.RecordData) { "[$($info.RecordData.SerialNumber)] $($info.RecordData.PrimaryServer), $($info.RecordData.ResponsiblePerson)" } else { "No SOA Information" } }
'SRV' { if ($info.RecordData.DomainName) { $info.RecordData.DomainName } else { "No Domain" } }
'PTR' { if ($info.RecordData.PtrDomainName) { $info.RecordData.PtrDomainName } else { "No PTR" } }
'MX' { if ($info.RecordData.MailExchange) { $info.RecordData.MailExchange } else { "No Mail Exchange" } }
'AAAA' { if ($info.RecordData.IPv6Address) { $info.RecordData.IPv6Address } else { "No IPv6" } }
'TXT' { if ($info.RecordData.DescriptiveText) { $info.RecordData.DescriptiveText } else { "No TXT" } }
default { "Unsupported record type: $($info.RecordType)" }
}
$ReportLine = [PSCustomObject]@{
Name = $zoneName
Hostname = $info.Hostname
Type = $info.RecordType
Data = $recordData
Timestamp = $timestamp
TimeToLive = $timetolive
}
$Report.Add($ReportLine)
} catch {
Write-Host "Error: An issue occurred while processing the record. Hostname: $($info.Hostname), Type: $($info.RecordType)" -ForegroundColor Red
Write-Host "Details: $_" -ForegroundColor Yellow
}
}
# Writing to CSV
try {
$Report | Export-Csv "C:\Script\DNSOperation\DNSZoneRecord.csv" -NoTypeInformation -Encoding utf8
Write-Host "DNS records have been successfully exported." -ForegroundColor Green
} catch {
Write-Host "Error: Failed to write to the CSV file." -ForegroundColor Red
throw $_
}
} catch {
Write-Host "An unexpected error occurred: $_" -ForegroundColor Red
}
These scripts might seem a bit complex, but the .csv data they generate can effectively meet your needs in situations requiring reporting or verification.
Reading data may not always be easier than working with a .csv file, but in the event of a zone deletion, our other script utilizing the Export-DnsServerZone and dnscmd commands will provide a quick recovery solution.
Recovery – Export Import Specific Zone
Export-DNSServerZone -name yusufustundag.com -FileName yusufustundagExport
After completing the export process, you can find the exported file under the C:\Windows\System32\dns directory.
Now, here’s a critical point: suppose you’ve exported all your zones using this method, but someone accidentally deleted one or more zones. How can you quickly recover them in such a scenario?
The script we will use for this recovery must include the zone name and the name of the exported zone, as shown below.
dnscmd /zoneadd "yusufustundag.com" /primary /file yusufustundagExport /Load
Add Reverse Lookup Zone
$Zones = @(
"1.1.0.0/24", # Subnet /24 (255.255.255.0)
"2.2.0.0/24",
"10.10.151.0/24"
)
foreach ($Zone in $Zones) {
try {
# Split the NetworkID and Subnet Mask
$SubnetArray = $Zone -split '/'
$IPAddress = $SubnetArray[0]
$SubnetMask = [int]$SubnetArray[1]
# Generate the Reverse Lookup Zone Name based on Subnet Mask
$Octets = $IPAddress -split '\.'
if ($SubnetMask -le 8) {
$RevZone = "$($Octets[0]).in-addr.arpa"
} elseif ($SubnetMask -le 16) {
$RevZone = "$($Octets[1]).$($Octets[0]).in-addr.arpa"
} elseif ($SubnetMask -le 24) {
$RevZone = "$($Octets[2]).$($Octets[1]).$($Octets[0]).in-addr.arpa"
} else {
$RevZone = "$($Octets[3]).$($Octets[2]).$($Octets[1]).$($Octets[0]).in-addr.arpa"
}
# Check if the Reverse Zone Already Exists
$ExistingZone = Get-DnsServerZone -Name $RevZone -ErrorAction SilentlyContinue
if ($ExistingZone) {
Write-Output "Reverse Lookup Zone '$RevZone' already exists."
} else {
# Add the Reverse Lookup Zone
Add-DnsServerPrimaryZone -NetworkID $Zone -ReplicationScope "Domain"
Write-Output "Reverse Lookup Zone '$RevZone' added successfully."
}
} catch {
# Handle Errors Gracefully
if ($_.Exception.Message -match "ResourceExists") {
Write-Output "Reverse Lookup Zone '$RevZone' already exists (error caught)."
} else {
Write-Error "Failed to add Reverse Lookup Zone '$RevZone': $_"
}
}
}
Have a nice day!