Skip to content

Cleaning Up Windows DNS Zones in PowerShell

    Several weeks ago, Allwire was called in to remediate malware attack that had wreaked havoc on the clients network. As part of the recovery process, we rebuilt all of the workstations and servers in the zone. Although the DNS servers remained functional throughout this ordeal, they were still polluted with several stale DNS A records over the last 60 days which we needed gone, while retaining a copy of the old zone analysis.

    To facilitate this, we crafted this nifty Powershell script. It’s quite straightforward to use—simply adjust the $ZoneName and NumberOfDaysBack variables to suit, and then unleash it on your most stale A records.

    (Remember, this script is not a one-stop solution for all DNS maintenance needs; it doesn’t replace the necessity for robust DNS scavenging and other best practices.)

    #MODIFY THESE
    $ZoneName = "yourdnszone.corp"
    $NumberOfDaysBack = 60
    #
    
    $DateInThePast = (Get-Date).AddDays(-$NumberOfDaysBack)
    # Provide record types separated by comma, variable can be leave empty
    $RecordTypes = "A"
    $RecordTypes = $RecordTypes.Split(',')
     
    if([string]::IsNullOrEmpty($RecordTypes))
    {
        $i = 0
        $RecordsArray = (Get-DnsServerResourceRecord -ZoneName $ZoneName |Where-Object {($_.Timestamp -lt $DateInThePast) -and ($_.Timestamp -ne $null)})[0]
        $RecordsArray | Export-Csv -Path $env:TEMP\$(Get-Date -Format dd_MM_yyyy)_$ZoneName'_AllRecords'.csv -NoTypeInformation
        $RecordsCounter = $RecordsArray.Count
        $Acceptance = Read-Host -Prompt "Do you want to remove $RecordsCounter records from $ZoneName zone? (Y/N)"
        if(($Acceptance -eq 'y') -or ($Acceptance -eq 'yes'))
        {
            foreach($Record in $RecordsArray)
            {
                $i++
                Write-Progress -Activity "Removing stale records from $ZoneName zone" -Status "Percent complete" -PercentComplete (($i/$RecordsCounter)*100)
                Try
                {
                    Remove-DnsServerResourceRecord -InputObject $Record -ZoneName $ZoneName -Force
                }
                Catch
                {
                    $_.Exception.Message
                }
            }
        }
        else
        {
            Write-Host Removing of stale records from $ZoneName zone has been skipped by user 
        }
    }
    else
    {
        foreach($RecordType in $RecordTypes)
        {
            $i = 0
            $RecordsArray = Get-DnsServerResourceRecord -ZoneName $ZoneName -RRType $RecordType |Where-Object {($_.Timestamp -lt $DateInThePast) -and ($_.Timestamp -ne $null)}
            $RecordsArray | Export-Csv -Path $env:TEMP\$(Get-Date -Format dd_MM_yyyy)_$ZoneName'_RecordType_'$RecordType.csv -NoTypeInformation
            $RecordsCounter = $RecordsArray.Count
            $Acceptance = Read-Host -Prompt "Do you want to remove $RecordsCounter $RecordType records from $ZoneName zone? (Y/N)"
            if(($Acceptance -eq 'y') -or ($Acceptance -eq 'yes'))
            {
                foreach($Record in $RecordsArray)
                {
                    $i++
                    Write-Progress -Activity "Removing stale $RecordType records from $ZoneName zone" -Status "Percent complete" -PercentComplete (($i/$RecordsCounter)*100)
                    Try
                    {
                        Remove-DnsServerResourceRecord -InputObject $Record -ZoneName $ZoneName -Force
                    }
                    Catch
                    {
                        $_.Exception.Message
                    }
                }
            }
            else
            {
                Write-Host Removing of stale $RecordType records from $ZoneName zone has been skipped by user 
            }
             
        }
    }
     
    Write-Host Script has been completed
    Write-Host All remove records have been exported to CSV files under path $env:TEMP
    
    Shameless Plug: Have a dirty DNS zone that needs scavenging? Feel free to get in contact with us!

    Leave a Reply

    Your email address will not be published. Required fields are marked *