Microsoft DNS & stale records

This post explains how to identify and report on stale records in a dynamically updated Microsoft DNS zone.

The time stamp taken from a DNS record represents the numbers of hours since 01/01/1601 00:00. The value can be converted into a useful date within a script. By default, all times are reported and tested in UTC.

A stale record is a record where both the No-Refresh Interval and Refresh Interval have passed without the time stamp updating. Ordinarily stale records would be removed by a Scavenging process. These scripts may be useful if trying to asses the impact of enabling Scavenging or reducing Aging intervals.

Listing stale records with VbScript

This script uses a WMI query to return all A records for a domain, then it sorts through each record, echoing when the time stamp is older than our pre-defined maximum age. The script will work best when run with cscript.

' No-Refresh + Refresh (in Days)
Const MAXIMUM_AGE = 4

' Connect to the MicrosoftDNS Namespace
Set objWMIService = _
  GetObject("winmgmts:\\dc01.internal.highorbit.co.uk\root\MicrosoftDNS")

' Query A records with MicrosoftDNS_AType class where the record is not static
Set colItems = objWMIService.ExecQuery("SELECT * FROM MicrosoftDNS_AType " &_
  " WHERE ContainerName='internal.highorbit.co.uk' AND TimeStamp<>0")

For Each objItem In colItems
  ' Convert the timestamp into a date and time
  dtmTimeStamp = DateAdd("h", objItem.TimeStamp, "01/01/1601 00:00:00")
  ' Compare the date and time with MAXIMUM_AGE
  If dtmTimeStamp <= (Date() - MAXIMUM_AGE) Then
    ' Echo the record details if it is older than the MAXIMUM_AGE
    WScript.Echo objItem.OwnerName & VbTab & objItem.IPAddress &_
      VbTab & dtmTimeStamp
  End If
Next

Listing stale records with PowerShell

This snippet uses Get-WMIObject and a improved query to return only stale records rather than sorting after returning all dynamic records.

A timespan value is generated to represent the minimum value of TimeStamp for valid records.

# No-Refresh + Refresh (in Days)
$TotalAgingInterval = 4

$ServerName = "dc01.internal.highorbit.co.uk"
$ContainerName = "internal.highorbit.co.uk"

$MinTimeStamp = [Int](New-TimeSpan `
  -Start $(Get-Date("01/01/1601 00:00")) `
  -End $((Get-Date).AddDays(-$TotalAgingInterval))).TotalHours

Get-WMIObject -Computer $ServerName `
  -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_AType" `
  -Filter `
  "ContainerName='$ContainerName' AND TimeStamp<$MinTimeStamp AND TimeStamp<>0" `
 | Select-Object OwnerName, `
  @{n="TimeStamp";e={(Get-Date("01/01/1601")).AddHours($_.TimeStamp)}}

Reading Aging intervals with PowerShell

The Aging intervals and the date the zone can be scavenged set on a zone can be read using WMI using the MicrosoftDNS_Zone class. As with the TimeStamp the .AddHours method must be used to return a date.

$ServerName = "dc01.internal.highorbit.co.uk"
$ContainerName = "internal.highorbit.co.uk"

Get-WMIObject -Computer $ServerName `
  -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_Zone" `
  -Filter "ContainerName='$ContainerName'" `
 | Select-Object NoRefreshInterval, RefreshInterval, `
  @{n="AvailForScavengeTime";e={
    (Get-Date("01/01/1601")).AddHours($_.AvailForScavengeTime)}}

Localisation

As mentioned at the beginning of this post, all times are reported in UTC by default. By calling a the ToLocalTime method the date returned can be converted to local time, using the time zone configured on the system executing the query.

$ServerName = "dc01.internal.highorbit.co.uk"
$ContainerName = "internal.highorbit.co.uk"

$MinTimeStamp = [Int](New-TimeSpan `
  -Start $(Get-Date("01/01/1601 00:00")) `
  -End $((Get-Date).AddDays(-$TotalAgingInterval))).TotalHours

Get-WMIObject -Computer $ServerName `
  -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_AType" `
  -Filter `
  "ContainerName='$ContainerName' AND TimeStamp<$MinTimeStamp AND TimeStamp<>0" `
 | Select-Object OwnerName, `
  @{n="TimeStamp";e={
    ((Get-Date("01/01/1601")).AddHours($_.TimeStamp)).ToLocalTime()}}

No related posts.

Related posts brought to you by Yet Another Related Posts Plugin.

Respond to this post