Windows DNS Name Server (NS) Record Management: Analysis & Reverse Lookup Zone Updates

Analyzing and Updating Name Server (NS) Records on Windows DNS Servers

Managing Windows DNS is crucial for ensuring that network infrastructures remain up-to-date and function correctly. The accuracy and timeliness of Name Server (NS) records are essential elements that must be frequently monitored. In this article, we will discuss how a script operates to analyze and update Name Server records on Windows DNS servers.

How Does the Script Work?

The developed script runs on Windows DNS servers and performs the following key operations:

  1. Scanning All Name Server Records:
    • When the “Analyze” button is pressed, the script scans all Forward Lookup Zone and Reverse Lookup Zone areas and lists the current Name Server (NS) records.
  2. Forward Lookup Zone and Reverse Lookup Zone Scanning:
    • It collects the existing Name Server records for the Forward Lookup Zone and Reverse Lookup Zone but does not make any modifications.
  3. Updating Reverse Lookup Zone:
    • When the “Update NS” button is pressed, the NS records in the Reverse Lookup Zone are checked.
    • Missing NS records are added.
    • Old and unused NS records are removed.
  4. Listing Old Name Server Records:
    • No updates are made for the Forward Lookup Zone, but outdated and unused NS records are displayed for the system administrator’s review.

Name Server Checker & Reverse Lookup Zone Update

# DNS Active NS Record Manager GUI Application

Add-Type -AssemblyName System.Windows.Forms

Add-Type -AssemblyName System.Drawing

# Create the main form

$form = New-Object System.Windows.Forms.Form

$form.Text = 'DNS Active NS Record Manager'

$form.Size = New-Object System.Drawing.Size(900,700)

$form.StartPosition = 'CenterScreen'

$form.FormBorderStyle = 'FixedDialog'

$form.MaximizeBox = $false

$form.BackColor = [System.Drawing.Color]::FromArgb(240,240,240)

# Create banner panel

$bannerPanel = New-Object System.Windows.Forms.Panel

$bannerPanel.Size = New-Object System.Drawing.Size(900,60)

$bannerPanel.Location = New-Object System.Drawing.Point(0,0)

$bannerPanel.BackColor = [System.Drawing.Color]::FromArgb(0,120,215)

$form.Controls.Add($bannerPanel)

# Create banner title

$bannerTitle = New-Object System.Windows.Forms.Label

$bannerTitle.Text = "DNS Active NS Record Management"

$bannerTitle.ForeColor = [System.Drawing.Color]::White

$bannerTitle.Font = New-Object System.Drawing.Font("Segoe UI", 16, [System.Drawing.FontStyle]::Regular)

$bannerTitle.AutoSize = $true

$bannerTitle.Location = New-Object System.Drawing.Point(20,15)

$bannerPanel.Controls.Add($bannerTitle)

# Create main panel for controls

$mainPanel = New-Object System.Windows.Forms.Panel

$mainPanel.Size = New-Object System.Drawing.Size(860,580)

$mainPanel.Location = New-Object System.Drawing.Point(20,80)

$mainPanel.BackColor = [System.Drawing.Color]::White

$form.Controls.Add($mainPanel)

# Create DNS Server label and textbox

$lblDNSServer = New-Object System.Windows.Forms.Label

$lblDNSServer.Location = New-Object System.Drawing.Point(20,20)

$lblDNSServer.Size = New-Object System.Drawing.Size(100,20)

$lblDNSServer.Text = 'DNS Server:'

$lblDNSServer.Font = New-Object System.Drawing.Font("Segoe UI", 9)

$mainPanel.Controls.Add($lblDNSServer)

$txtDNSServer = New-Object System.Windows.Forms.TextBox

$txtDNSServer.Location = New-Object System.Drawing.Point(120,20)

$txtDNSServer.Size = New-Object System.Drawing.Size(200,20)

$txtDNSServer.Text = 'localhost'

$txtDNSServer.Font = New-Object System.Drawing.Font("Segoe UI", 9)

$mainPanel.Controls.Add($txtDNSServer)

# Create Active NS Servers ListView

$lblActiveNS = New-Object System.Windows.Forms.Label

$lblActiveNS.Location = New-Object System.Drawing.Point(20,60)

$lblActiveNS.Size = New-Object System.Drawing.Size(150,20)

$lblActiveNS.Text = 'Active NS Servers:'

$lblActiveNS.Font = New-Object System.Drawing.Font("Segoe UI", 9)

$mainPanel.Controls.Add($lblActiveNS)

$listActiveNS = New-Object System.Windows.Forms.ListView

$listActiveNS.Location = New-Object System.Drawing.Point(20,85)

$listActiveNS.Size = New-Object System.Drawing.Size(400,150)

$listActiveNS.View = [System.Windows.Forms.View]::Details

$listActiveNS.FullRowSelect = $true

$listActiveNS.GridLines = $true

$listActiveNS.Font = New-Object System.Drawing.Font("Segoe UI", 9)

$listActiveNS.Columns.Add("NS Server", 380)

$mainPanel.Controls.Add($listActiveNS)

# Create button panel

$buttonPanel = New-Object System.Windows.Forms.Panel

$buttonPanel.Size = New-Object System.Drawing.Size(420,30)

$buttonPanel.Location = New-Object System.Drawing.Point(440,85)

$buttonPanel.BackColor = [System.Drawing.Color]::White

$mainPanel.Controls.Add($buttonPanel)

# Create Refresh button

$btnRefresh = New-Object System.Windows.Forms.Button

$btnRefresh.Location = New-Object System.Drawing.Point(0,0)

$btnRefresh.Size = New-Object System.Drawing.Size(100,30)

$btnRefresh.Text = 'Refresh'

$btnRefresh.FlatStyle = 'Flat'

$btnRefresh.BackColor = [System.Drawing.Color]::FromArgb(0,120,215)

$btnRefresh.ForeColor = [System.Drawing.Color]::White

$btnRefresh.Font = New-Object System.Drawing.Font("Segoe UI", 9)

$btnRefresh.Cursor = [System.Windows.Forms.Cursors]::Hand

$buttonPanel.Controls.Add($btnRefresh)

# Create Analyze button

$btnAnalyze = New-Object System.Windows.Forms.Button

$btnAnalyze.Location = New-Object System.Drawing.Point(105,0)

$btnAnalyze.Size = New-Object System.Drawing.Size(100,30)

$btnAnalyze.Text = 'Analyze'

$btnAnalyze.FlatStyle = 'Flat'

$btnAnalyze.BackColor = [System.Drawing.Color]::FromArgb(0,120,215)

$btnAnalyze.ForeColor = [System.Drawing.Color]::White

$btnAnalyze.Font = New-Object System.Drawing.Font("Segoe UI", 9)

$btnAnalyze.Cursor = [System.Windows.Forms.Cursors]::Hand

$buttonPanel.Controls.Add($btnAnalyze)

# Create Clean button

$btnClean = New-Object System.Windows.Forms.Button

$btnClean.Location = New-Object System.Drawing.Point(210,0)

$btnClean.Size = New-Object System.Drawing.Size(100,30)

$btnClean.Text = 'Update NS'

$btnClean.FlatStyle = 'Flat'

$btnClean.BackColor = [System.Drawing.Color]::FromArgb(0,120,215)

$btnClean.ForeColor = [System.Drawing.Color]::White

$btnClean.Font = New-Object System.Drawing.Font("Segoe UI", 9)

$btnClean.Enabled = $false

$btnClean.Cursor = [System.Windows.Forms.Cursors]::Hand

$buttonPanel.Controls.Add($btnClean)

# Create Exit button

$btnExit = New-Object System.Windows.Forms.Button

$btnExit.Location = New-Object System.Drawing.Point(315,0)

$btnExit.Size = New-Object System.Drawing.Size(100,30)

$btnExit.Text = 'Exit'

$btnExit.FlatStyle = 'Flat'

$btnExit.BackColor = [System.Drawing.Color]::FromArgb(232,17,35)

$btnExit.ForeColor = [System.Drawing.Color]::White

$btnExit.Font = New-Object System.Drawing.Font("Segoe UI", 9)

$btnExit.Cursor = [System.Windows.Forms.Cursors]::Hand

$buttonPanel.Controls.Add($btnExit)

# Create RichTextBox for output

$txtOutput = New-Object System.Windows.Forms.RichTextBox

$txtOutput.Location = New-Object System.Drawing.Point(20,250)

$txtOutput.Size = New-Object System.Drawing.Size(820,310)

$txtOutput.ReadOnly = $true

$txtOutput.BackColor = [System.Drawing.Color]::FromArgb(30,30,30)

$txtOutput.ForeColor = [System.Drawing.Color]::White

$txtOutput.Font = New-Object System.Drawing.Font("Consolas", 10)

$txtOutput.BorderStyle = 'None'

$mainPanel.Controls.Add($txtOutput)

# Function to write colored output

function Write-ColorOutput {

    param([string]$Message, [string]$Color = "White")

    $txtOutput.SelectionColor = [System.Drawing.Color]::$Color

    $txtOutput.AppendText("$Message`n")

    $txtOutput.ScrollToCaret()

}

# Function to write separator line

function Write-Separator {

    Write-ColorOutput ("-" * 80) "DarkGray"

}

# Function to test if a server is online with simple checks

function Test-ServerConnection {

    param([string]$ServerName)

    try {

        Write-ColorOutput "Testing NS server: $ServerName" "Yellow"

        

        # Try to get IP address

        try {

            $ipAddress = [System.Net.Dns]::GetHostAddresses($ServerName) |

                        Where-Object { $_.AddressFamily -eq 'InterNetwork' } |

                        Select-Object -First 1

            

            if ($ipAddress) {

                Write-ColorOutput "  - IP Address: $($ipAddress.IPAddressToString)" "Gray"

            } else {

                Write-ColorOutput "  - Could not resolve IP address" "Red"

                return $false

            }

        } catch {

            Write-ColorOutput "  - DNS resolution failed" "Red"

            return $false

        }

        

        # Try ping

        $ping = Test-Connection -ComputerName $ServerName -Count 2 -Quiet

        if ($ping) {

            Write-ColorOutput "  - Ping successful" "Green"

            

            # Try basic DNS port check

            try {

                $tcp = New-Object System.Net.Sockets.TcpClient

                $tcp.SendTimeout = 2000

                $tcp.ReceiveTimeout = 2000

                $result = $tcp.BeginConnect($ServerName, 53, $null, $null)

                $success = $result.AsyncWaitHandle.WaitOne(2000, $false)

                if ($success) {

                    Write-ColorOutput "  - DNS port is accessible" "Green"

                    $tcp.EndConnect($result)

                    return $true

                } else {

                    Write-ColorOutput "  - DNS port is not accessible" "Red"

                    return $false

                }

            } catch {

                Write-ColorOutput "  - DNS port check failed" "Red"

                return $false

            } finally {

                if ($tcp) { $tcp.Close() }

            }

        } else {

            Write-ColorOutput "  - Ping failed" "Red"

            return $false

        }

    } catch {

        Write-ColorOutput "  - Connection test failed: $_" "Red"

        return $false

    }

}

# Function to validate NS server with simple logic

function Test-NSServerValidity {

    param([string]$NSServer)

    return Test-ServerConnection -ServerName $NSServer

}

# Function to get active NS records

function Get-ActiveNSRecords {

    $listActiveNS.Items.Clear()

    Write-ColorOutput "Loading active NS records..." "Yellow"

    Write-Separator

    

    try {

        # Get all zones (both forward and reverse)

        $allZones = Get-DnsServerZone -ComputerName $txtDNSServer.Text |

                   Where-Object { $_.ZoneName -ne "TrustAnchors" }

        

        $script:activeNSServers = @()

        $script:inactiveNSServers = @{}  # Track inactive NS servers and their source zones

        $potentialNSServers = @{}

        

        foreach ($zone in $allZones) {

            Write-ColorOutput "Checking zone: $($zone.ZoneName)" "Cyan"

            

            # Get NS records for each zone

            $nsRecords = Get-DnsServerResourceRecord -ZoneName $zone.ZoneName -RRType "NS" -ComputerName $txtDNSServer.Text |

                        Where-Object { $_.RecordType -eq "NS" }

            

            foreach ($ns in $nsRecords) {

                $nsHost = $ns.RecordData.NameServer.Trim('.')

                if (-not $potentialNSServers.ContainsKey($nsHost)) {

                    $potentialNSServers[$nsHost] = $zone.ZoneName

                }

            }

        }

        

        Write-ColorOutput "`nValidating NS servers..." "Yellow"

        Write-Separator

        

        foreach ($nsServer in $potentialNSServers.Keys) {

            Write-ColorOutput "Processing NS server from zone '$($potentialNSServers[$nsServer])'" "Cyan"

            

            if (Test-NSServerValidity -NSServer $nsServer) {

                if (-not $script:activeNSServers.Contains($nsServer)) {

                    $script:activeNSServers += $nsServer

                    $listActiveNS.Items.Add($nsServer)

                    Write-ColorOutput "Confirmed active NS: $nsServer" "Green"

                }

            } else {

                Write-ColorOutput "NS server validation failed: $nsServer" "Red"

                if (-not $script:inactiveNSServers.ContainsKey($nsServer)) {

                    $script:inactiveNSServers[$nsServer] = $potentialNSServers[$nsServer]

                }

            }

            Write-Separator

        }

        

        Write-ColorOutput "`nTotal active NS servers found: $($script:activeNSServers.Count)" "Cyan"

        Write-ColorOutput "Active NS Servers:" "Yellow"

        foreach ($ns in $script:activeNSServers) {

            Write-ColorOutput "  $ns" "White"

        }

        Write-Separator

        

    } catch {

        Write-ColorOutput "Error getting active NS records: $_" "Red"

        Write-Separator

    }

}

# Function to analyze DNS zones

function Analyze-ReverseLookupZones {

    Write-ColorOutput "Starting DNS zone analysis..." "Yellow"

    Write-Separator

    

    try {

        # Get all zones for information

        $allZones = Get-DnsServerZone -ComputerName $txtDNSServer.Text |

                   Where-Object { $_.ZoneName -ne "TrustAnchors" }

        

        # Get only reverse lookup zones for updates

        $reverseLookupZones = $allZones | Where-Object { $_.ZoneName -like "*.in-addr.arpa" }

        

        $script:inactiveNSCount = 0

        $script:analyzedZones = @{}  # Will only contain reverse lookup zones

        $script:zonesToUpdate = @{}  # Will only contain reverse lookup zones

        

        # First, show inactive NS servers from all zones (informational)

        Write-ColorOutput "`nInactive NS Servers in All Zones (Informational):" "Yellow"

        Write-Separator

        foreach ($inactiveNS in $script:inactiveNSServers.Keys) {

            Write-ColorOutput "Found inactive NS server: $inactiveNS" "Red"

            Write-ColorOutput "Originally detected in zone: $($script:inactiveNSServers[$inactiveNS])" "Yellow"

            Write-Separator

        }

        

        # Process all zones for information

        Write-ColorOutput "`nAnalyzing All Zones (Informational):" "Yellow"

        Write-Separator

        foreach ($zone in $allZones) {

            if ($zone.ZoneName -notlike "*.in-addr.arpa") {

                Write-ColorOutput "Checking zone: $($zone.ZoneName)" "Cyan"

                

                $nsRecords = Get-DnsServerResourceRecord -ZoneName $zone.ZoneName -RRType "NS" -ComputerName $txtDNSServer.Text |

                            Where-Object { $_.RecordType -eq "NS" }

                

                foreach ($ns in $nsRecords) {

                    $nsHost = $ns.RecordData.NameServer.Trim('.')

                    if ($script:inactiveNSServers.ContainsKey($nsHost)) {

                        Write-ColorOutput "  - Inactive NS found: $nsHost" "Red"

                    } else {

                        Write-ColorOutput "  - Active NS found: $nsHost" "Green"

                    }

                }

                Write-Separator

            }

        }

        

        # Process reverse lookup zones for updates

        Write-ColorOutput "`nAnalyzing Reverse Lookup Zones (Will Be Updated):" "Yellow"

        Write-Separator

        foreach ($zone in $reverseLookupZones) {

            Write-ColorOutput "Analyzing zone: $($zone.ZoneName)" "Cyan"

            

            $nsRecords = Get-DnsServerResourceRecord -ZoneName $zone.ZoneName -RRType "NS" -ComputerName $txtDNSServer.Text |

                        Where-Object { $_.RecordType -eq "NS" }

            

            $inactiveNS = @()

            $existingNS = @()

            $missingNS = @()

            

            # Check for inactive NS records

            foreach ($ns in $nsRecords) {

                $nsHost = $ns.RecordData.NameServer.Trim('.')

                $existingNS += $nsHost

                

                if ($script:inactiveNSServers.ContainsKey($nsHost) -or -not $script:activeNSServers.Contains($nsHost)) {

                    $inactiveNS += $nsHost

                    $script:inactiveNSCount++

                    Write-ColorOutput "  - Inactive NS found: $nsHost" "Red"

                } else {

                    Write-ColorOutput "  - Active NS found: $nsHost" "Green"

                }

            }

            

            # Check for missing active NS records

            foreach ($activeNS in $script:activeNSServers) {

                if (-not $existingNS.Contains($activeNS)) {

                    $missingNS += $activeNS

                    Write-ColorOutput "  + Missing active NS: $activeNS" "Yellow"

                }

            }

            

            if ($inactiveNS.Count -gt 0) {

                $script:analyzedZones[$zone.ZoneName] = $inactiveNS

            }

            

            if ($missingNS.Count -gt 0) {

                $script:zonesToUpdate[$zone.ZoneName] = $missingNS

            }

            

            if ($inactiveNS.Count -eq 0 -and $missingNS.Count -eq 0) {

                Write-ColorOutput "  Zone is properly configured." "Green"

            }

            Write-Separator

        }

        

        Write-ColorOutput "`nAnalysis Summary:" "Cyan"

        Write-ColorOutput "Total zones analyzed: $($allZones.Count)" "White"

        Write-ColorOutput "Reverse lookup zones to update: $($reverseLookupZones.Count)" "White"

        Write-ColorOutput "Total inactive NS records in reverse zones: $script:inactiveNSCount" "Yellow"

        Write-ColorOutput "Total reverse zones needing NS records: $($script:zonesToUpdate.Count)" "Yellow"

        Write-Separator

        

        if ($script:inactiveNSCount -gt 0 -or $script:zonesToUpdate.Count -gt 0) {

            $btnClean.Enabled = $true

        } else {

            $btnClean.Enabled = $false

        }

        

    } catch {

        Write-ColorOutput "Error analyzing zones: $_" "Red"

        Write-Separator

    }

}

# Function to clean inactive NS records and add missing ones

function Clean-InactiveNSRecords {

    if ([System.Windows.Forms.MessageBox]::Show(

        "Are you sure you want to update NS records in reverse lookup zones?`n`nThis will:`n- Remove inactive NS records from reverse lookup zones`n- Add missing active NS records to reverse lookup zones`n`nOther zones will not be modified.",

        "Confirm Update",

        [System.Windows.Forms.MessageBoxButtons]::YesNo,

        [System.Windows.Forms.MessageBoxIcon]::Warning) -eq 'Yes')

    {

        Write-ColorOutput "Starting reverse lookup zone NS records update..." "Yellow"

        Write-Separator

        

        try {

            $removedCount = 0

            $addedCount = 0

            

            # Process only reverse lookup zones

            foreach ($zone in $script:analyzedZones.Keys) {

                Write-ColorOutput "Processing zone: $zone" "Cyan"

                

                foreach ($inactiveNS in $script:analyzedZones[$zone]) {

                    try {

                        Remove-DnsServerResourceRecord -ZoneName $zone -RRType "NS" -Name "@" `

                            -RecordData $inactiveNS -Force -ComputerName $txtDNSServer.Text

                        Write-ColorOutput "Removed NS record: $inactiveNS" "Green"

                        $removedCount++

                    } catch {

                        Write-ColorOutput "Error removing NS record $inactiveNS : $_" "Red"

                    }

                }

            }

            

            foreach ($zone in $script:zonesToUpdate.Keys) {

                Write-ColorOutput "`nAdding missing NS records to zone: $zone" "Cyan"

                

                foreach ($missingNS in $script:zonesToUpdate[$zone]) {

                    try {

                        Add-DnsServerResourceRecord -ZoneName $zone -NS -Name "@" `

                            -NameServer $missingNS -ComputerName $txtDNSServer.Text

                        Write-ColorOutput "Added NS record: $missingNS" "Green"

                        $addedCount++

                    } catch {

                        Write-ColorOutput "Error adding NS record $missingNS : $_" "Red"

                    }

                }

            }

            

            Write-ColorOutput "`nUpdate Summary:" "Cyan"

            Write-ColorOutput "Total NS records removed from reverse zones: $removedCount" "Yellow"

            Write-ColorOutput "Total NS records added to reverse zones: $addedCount" "Yellow"

            Write-Separator

            

            $btnClean.Enabled = $false

            $script:analyzedZones.Clear()

            $script:zonesToUpdate.Clear()

            $script:inactiveNSCount = 0

            

        } catch {

            Write-ColorOutput "Error during update: $_" "Red"

            Write-Separator

        }

    }

}

# Button click events

$btnRefresh.Add_Click({ Get-ActiveNSRecords })

$btnAnalyze.Add_Click({ Analyze-ReverseLookupZones })

$btnClean.Add_Click({ Clean-InactiveNSRecords })

$btnExit.Add_Click({ $form.Close() })

# Load active NS records when form loads

$form.Add_Shown({

    Get-ActiveNSRecords

})

# Show the form

$form.ShowDialog() 

 

What Is the Purpose of This Script?

This script was developed to improve DNS management efficiency. Over time, DNS servers may experience performance issues due to outdated records, making regular updates crucial. It is particularly useful in the following scenarios:

  • When making major changes to the network.
  • When updating existing Name Server records.
  • When identifying and removing old NS records.
  • When regularly optimizing Reverse Lookup Zone areas.

As a result, with this script

To ensure that Windows DNS servers function correctly, NS records must be continuously monitored and updated. This script provides a great convenience for DNS administrators by offering both analysis and update functions. Using automation like this to keep your DNS infrastructure healthy and up to date is highly beneficial.

If you found this trick helpful, feel free to share it with your team and check out my blog for more quick tips and insights!

Efficient DNS Zone Management: Scripts for Forward, Reverse Lookup Zones and Recovery

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!