Emergency server help: get in touch

AD DNS Scavenging: Safe Aging Setup with PowerShell

Set up DNS aging and scavenging on AD-integrated zones safely: timers explained, a three-phase rollout with PowerShell, protecting static records, and events 2501/2502.

Published 9 min read

Short answer: Stale records in AD-integrated DNS zones are removed only when three things are true: aging is on for the zone (Set-DnsServerZoneAging -Aging $true), scavenging is on for at least one DNS server (Set-DnsServerScavenging -ScavengingState $true), and the record has a non-zero timestamp older than no-refresh + refresh interval (7 + 7 days by default). Roll it out safely: enable aging only, wait one full no-refresh + refresh period, check which records would go, restrict scavenging to one DC with -ScavengeServers, then switch scavenging on and watch DNS Server events 2501 and 2502.

We ran these commands on 6 October 2026 on a Windows Server 2025 Standard domain controller (build 26100.33438, September 2026 update, Windows PowerShell 5.1) and a Windows 11 Pro member PC in our lab domain contoso.com. Where the lab result differed from the documentation, the page says so.

How aging and scavenging decide what to delete

Dynamic DNS fills AD-integrated zones automatically, but nothing removes a record when the computer that registered it is gone. AD replication does not clean up either. Over time you get duplicate A records for the same IP, stale PTRs, and helpdesk tickets that end in “the name points at the wrong machine”. Aging and scavenging fix that, but only if you understand the timers.

TermMeaningDefault
TimestampSet on every dynamically registered record, rounded to the hour. Static (manual) records have timestamp 0 and are never scavenged.n/a
No-refresh intervalAfter a timestamp is set, refreshes that do not change the data are ignored. Cuts replication traffic.7 days
Refresh intervalWindow after no-refresh during which the client must refresh its record.7 days
Scavenging periodHow often a scavenging server runs a pass. Resets when the DNS service restarts.7 days
Available for scavenging timePer-zone time after which scavenging may touch the zone: time aging was enabled (rounded down) + refresh interval.n/a

A record is deleted when timestamp + no-refresh + refresh < now and a scavenging pass runs on a server allowed to scavenge that zone. With defaults, a dead record becomes stale after 14 days and may survive up to about 21 days. Windows clients refresh their own records every 24 hours, so a live machine never gets close.

Aging and scavenging are both off by default. Microsoft warns that a misconfiguration can delete legitimate records, which is why the rollout below is deliberately slow.

Check the current state

Run these on a DC that hosts DNS (or add -ComputerName dc01):

Get-DnsServerScavenging

Get-DnsServerZone | Where-Object { -not $_.IsAutoCreated -and $_.ZoneType -eq 'Primary' } | ForEach-Object {
    $a = Get-DnsServerZoneAging -Name $_.ZoneName
    [pscustomobject]@{
        Zone            = $_.ZoneName
        ADIntegrated    = $_.IsDsIntegrated
        DynamicUpdate   = $_.DynamicUpdate
        Aging           = $a.AgingEnabled
        NoRefresh       = $a.NoRefreshInterval
        Refresh         = $a.RefreshInterval
        ScavengeServers = ($a.ScavengeServers -join ', ')
        AvailableAfter  = $a.AvailForScavengeTime
    }
} | Format-Table -AutoSize

Server-level scavenging does not replicate: check every DNS server. Zone aging on an AD-integrated zone does replicate, so you set it once.

Before changing anything, make sure AD replication is healthy (repadmin /replsummary, see dcdiag and repadmin health check) and export the zones you are about to scavenge:

# Writes contoso.local.bak.dns to %windir%\System32\dns on the DNS server
Export-DnsServerZone -Name 'contoso.local' -FileName 'contoso.local.bak.dns' 

Phase 1: enable aging only

Make sure no server is scavenging yet, then turn on aging for the zones you want to clean. This starts the clock without deleting anything.

# 1. Confirm server scavenging is off on every DNS server
Get-DnsServerScavenging | Select-Object ScavengingState, ScavengingInterval

# 2. Restrict who may scavenge the zone to one DC (by IP)
Set-DnsServerZoneAging -Name 'contoso.local' -Aging $true `
    -NoRefreshInterval 7.00:00:00 -RefreshInterval 7.00:00:00 `
    -ScavengeServers 192.168.1.10

# Repeat for reverse zones you want to clean
Set-DnsServerZoneAging -Name '1.168.192.in-addr.arpa' -Aging $true `
    -NoRefreshInterval 7.00:00:00 -RefreshInterval 7.00:00:00 `
    -ScavengeServers 192.168.1.10

Choosing intervals:

  • Keep refresh at least as long as the longest time a legitimate machine can be offline and still matter (laptops on holiday, lab servers powered off for a week). Microsoft’s advice is to leave the refresh interval at the default and lower no-refresh if you want faster cleanup.
  • Relate it to DHCP lease duration. A Microsoft field engineer’s write-up shows how a lease shorter than no-refresh + refresh lets a new client get an IP whose old record still exists, producing two names on one IP. Either keep leases at or above the combined interval or make sure DHCP registers and removes records itself.
  • The same zone setting applies to every record type, including SRV records registered by DCs, which refresh themselves regularly.

Avoid dnscmd /ageallrecords and Set-DnsServerResourceRecordAging -Recurse on a whole zone. Both stamp every record, including static ones you deliberately created (servers, printers, MX, CNAME targets), making them eligible for deletion.

Phase 2: find out what would be deleted

Wait until the zone’s AvailForScavengeTime has passed and at least one full no-refresh + refresh period (14 days with defaults) has elapsed since you enabled aging. Then list dynamic records whose timestamp is already old enough to be scavenged:

$zone   = 'contoso.local'
$aging  = Get-DnsServerZoneAging -Name $zone
$cutoff = (Get-Date) - $aging.NoRefreshInterval - $aging.RefreshInterval

Get-DnsServerResourceRecord -ZoneName $zone |
    Where-Object { $_.Timestamp -and $_.Timestamp -lt $cutoff } |
    Select-Object HostName, RecordType, Timestamp,
        @{n='Data';e={ $_.RecordData.IPv4Address, $_.RecordData.HostNameAlias, $_.RecordData.DomainName | Where-Object { $_ } | Select-Object -First 1 }} |
    Sort-Object Timestamp |
    Export-Csv .\would-be-scavenged.csv -NoTypeInformation

Go through the CSV. Every record on it must be explainable as genuinely dead. Microsoft’s setup article lists what to check when you find a record that should not be there:

  • Does ipconfig /registerdns on that machine work? If not, fix dynamic registration first (DNS client settings, firewall, secure update permissions).
  • Who owns the record (record properties > Security)? A record created by an admin and later set to age may not be updatable by the computer.
  • Is AD replication healthy for that DC?
  • Is it a static record someone accidentally aged? Protect it as shown below.

Do not continue until the list contains only records you are happy to lose.

Protect records that must never be scavenged

A record is protected when its timestamp is zero. In DNS Manager (View > Advanced), open the record and clear Delete this record when it becomes stale. With PowerShell there is no single cmdlet that clears a timestamp; Microsoft’s documented method is to recreate the record as static:

# Capture the existing record first
Get-DnsServerResourceRecord -ZoneName 'contoso.local' -Name 'printsrv01' -RRType A

# Recreate as static (no -AgeRecord means timestamp 0)
Remove-DnsServerResourceRecord -ZoneName 'contoso.local' -Name 'printsrv01' -RRType A -Force
Add-DnsServerResourceRecordA -ZoneName 'contoso.local' -Name 'printsrv01' -IPv4Address 192.168.1.40

Removing and re-adding a record briefly removes the name and changes the record’s owner and permissions, which can stop the original computer updating it later. Do it in a quiet period and only for records that should be static anyway.

Phase 3: enable scavenging on one DC

Turn on scavenging on the single server you listed in -ScavengeServers. Do not use -ApplyOnAllZones here, because that pushes aging settings to every zone on the server, including zones you have not reviewed.

# On DC01 (192.168.1.10) only
Set-DnsServerScavenging -ScavengingState $true -ScavengingInterval 7.00:00:00

# Optional: run a pass now instead of waiting for the schedule
Start-DnsServerScavenging -Force -Verbose

Start-DnsServerScavenging asks for confirmation; -Force skips the prompt, which matters in a script or a remote session (without it the command fails with “PowerShell is in NonInteractive mode”). In our lab the first run printed “Scavenging has been configured for this server. Remember to enable aging on individual zones”.

A manual pass does not bypass any of the safety checks: zones that are not yet past their available-for-scavenging time, have aging off, or list a different scavenging server are skipped. One scavenging server per zone is Microsoft’s recommendation: one schedule, one event log to read.

Check that it worked

After each pass the DNS server logs event 2501 (records were scavenged) or 2502 (a pass ran, nothing was stale) in the DNS Server log:

Get-WinEvent -FilterHashtable @{ LogName = 'DNS Server'; Id = 2501, 2502 } -MaxEvents 10 |
    Format-Table TimeCreated, Id, Message -Wrap
  • Add the scavenging period to the latest 2501/2502 time to know when the next pass runs.
  • Create a test record with aging (Add-DnsServerResourceRecordA -ZoneName contoso.local -Name scavtest -IPv4Address 192.168.1.250 -AgeRecord), work out timestamp + no-refresh + refresh, and confirm it disappears at the first pass after that time.
  • Rerun the Phase 2 query: the old records should be gone and the CSV empty or close to it.
  • Spot-check that important names (DCs, file servers, printers) still resolve: Resolve-DnsName fs01.contoso.local.

Common problems

  • Scavenging is on but nothing is ever deleted (only 2502). The zone has aging off, the server is not in the zone’s scavenge servers list, the available-for-scavenging time has not passed, or the records have timestamp 0.
  • Records of live machines disappear. The client is not refreshing (stopped DNS Client service, DHCP registering on its behalf with different credentials, or a record owned by another account), or the refresh interval is shorter than how long machines stay offline. Restore from the zone export or AD Recycle Bin and fix registration before re-enabling.
  • Duplicate records for one IP. Typically DHCP lease shorter than no-refresh + refresh. Align the durations or have DHCP manage registrations.
  • Server-level settings seem to “revert”. Scavenging is per server and the period resets when the DNS service restarts; it is not replicated through AD.

Official documentation: DNS aging and scavenging · Configure DNS aging and scavenging · DNS scavenging setup (troubleshooting) · Set-DnsServerZoneAging

Related: Windows DHCP Failover Between Two Servers: Reliable Setup · dcdiag repadmin Health Check: 7 Critical Tests Explained · Find Inactive AD Users and Computers: PowerShell Cleanup in 5 Steps · Enable and use the Active Directory Recycle Bin to restore deleted objects · Change Domain Controller IP Address Safely

See also: AD Health Check Report: dcdiag and repadmin PowerShell Script

Frequently asked questions

What are good no-refresh and refresh intervals?

The 7-day defaults suit most networks. Microsoft suggests lowering no-refresh rather than refresh if you need faster cleanup, and the refresh interval should cover the longest time a valid machine stays offline.

Do I need scavenging on every domain controller?

No. Enable it on one DNS server and restrict each zone to that server with -ScavengeServers. Zone aging on AD-integrated zones replicates; server scavenging does not.

Will scavenging delete my static records?

Not unless they have a non-zero timestamp. Manually created records have timestamp 0. They become eligible only if someone aged them, for example with dnscmd /ageallrecords.

How do I undo an accidental scavenge?

Restore the records from your zone export or, for AD-integrated zones, recover the dnsNode objects with the AD Recycle Bin if it is enabled, then re-register clients with ipconfig /registerdns.

Why does my test record not disappear exactly on time?

It is deleted at the first scavenging pass after timestamp + no-refresh + refresh. Passes happen once per scavenging period, so allow up to one extra period.

Free website test

Is your website set up right?

Check SSL, security headers, redirects, robots.txt, sitemap, llms.txt and security.txt in one test. It takes about 30 seconds.