Querying and identifying static DNS records with PowerShell

DNS is closely integrated with Microsoft Active Directory. When you perform a health check of Active Directory systems, it becomes necessary to include health check items associated with the DNS servers. For example, you might want to check whether all DNS servers have scavenging enabled or not. Similarly, you might also want to check as to how many DNS stale records you have in Active Directory Domain Zones. Another health check item pertaining to DNS server is to make sure you don’t have static DNS entries created for Windows client computers. Apart from checking the above mentioned DNS server health check items, you can also check to make sure the Active Directory domain zone has secure updates enabled. In this article, we will explain how you can use a simple PowerShell script to get a list of static DNS entries created in the DNS server and then identify the static entries that are no longer needed.

You can always create static DNS records for systems that cannot refresh/update their DNS records dynamically such as Linux operating systems, but it makes no sense to create static DNS entries for Windows client computers. Windows client computers can easily refresh/update their DNS records in the DNS Server. You can use the below PowerShell script to get a list of static DNS A and CNAME records from the current DNS domain zone.

Requirements to find static DNS records

Before you can run the script, please make sure to meet the requirements mentioned below:

  • Ensure you are running the script from a Windows Server 2012 R2 member server or domain controller.
  • You must install DNS Server tools from Server Manager. Note that below script uses Get-DNSServerResourceRecord PowerShell cmdlet, which is installed as part of DNS Server Tools.
  • Make sure to create a folder by name “C:\Temp” on the computer from where you will run the script.
  • Create a text file by name DomList.txt and specify the name of domain zones in it.
  • Make sure PDC Emulator of the Active Directory domain is reachable. Note that it is always recommended to perform Active Directory-related operations against PDC Emulator.

Once you have met above requirements, copy the below script in a PS1 file and execute it from an elevated PowerShell window.

### Script Starts Here ###

$TestCSVFile = “C:\Temp\DNSStaticEntries.CSV”
Remove-item $TestCSVFile -ErrorAction SilentlyContinue
$GDomList = “C:\Temp\DomList.TXT”

$ThisString=”Domain Zone, Connected to PDC, Number of Static CNAME Entries, Number of Static A DNS Entries, Static Record File,Final Status”
Add-Content “$TestCSVFile” $ThisString

$TotNo=0
$ItemCount=0
$TestText = “”
$TestStatus=””
$SumVal = “”
$AnyGap = “No”

ForEach ($ThisDomain in Get-Content “$GDomList”)
{

$PDCServerToConnect = “Unknown”
IF ($HitWin2012DC -eq “Yes” -and $CredInputForPS -eq “File”)
{
$PrefDCFile = C:\Temp\None.Txt
Add-Content $PrefDCFile “None”
$PDCCSV = Import-CSV $PrefDCFile
ForEach ($ItemNow in $PDCCSV)
{
IF ($ItemNow.Domain -eq $ThisDomain)
{
$PDCServerToConnect = $ItemNow.’Preferred Domain Controller’
break
}
}

}
else
{
$PDCCSV = Import-CSV $PDCListFile
ForEach ($ItemNow in $PDCCSV)
{
IF ($ItemNow.Domain -eq $ThisDomain)
{
$PDCServerToConnect = $ItemNow.PDCServer
break
}
}
}

$Error.Clear()
$StaticARecords = Get-DnsServerResourceRecord -ZoneName $ThisDomain -ComputerName $PDCServerToConnect -RRType A | Where Timestamp -eq $Null | Select -Property HostName,RecordType -ExpandProperty RecordData
IF ($Error.count -eq 0)
{
$StaticCNAMERecords = Get-DnsServerResourceRecord -ZoneName $ThisDomain -ComputerName $PDCServerToConnect -RRType CNAME | Where Timestamp -eq $Null | Select -Property HostName,RecordType -ExpandProperty RecordData

$StaticACount = $StaticARecords.Count
$StaticCNAMECount = $StaticCNAMERecords.Count

$OkOrNot=”Ok”
IF ($StaticACount -ne 0 -or $StaticCNAMECount -ne 0)
{
$AnyGap = “Yes”
$OkOrNot = “NO”
}

$StaticZoneAFile = “C:\Temp\”+$CurProfNowForAll+”_StaticRecords_A”+$ThisDomain+”.CSV”
IF (Test-path $StaticZoneAFile)
{
Remove-item $StaticZoneAFile
}

$StaticZoneCNAMEFile = “C:\ProgramData\DynamicPacksTechnologies\ADHealthProfiler\Data\DNSStaticRecordsTest\”+$CurProfNowForAll+”_StaticRecords_CNAME”+$ThisDomain+”.CSV”
IF (Test-path $StaticZoneCNAMEFile)
{
Remove-item $StaticZoneCNAMEFile
}

$StaticARecords | Export-CSV $StaticZoneAFile -Append -NoTypeInfo
$StaticCNAMERecords | Export-CSV $StaticZoneCNAMEFile -Append -NoTypeInfo

$FinStatus=””
IF ($OkOrNot -eq “NO”)
{
$FinStatus =”Found Static Records in Domain Zones.”
}

$FinalSTR =$ThisDomain+”,”+$PDCServerToConnect+”,”+$StaticCNAMECount+”,”+$StaticACount+”,”+$StaticZoneAFile+”;”+$StaticZoneCNAMEFile+”,”+$FinStatus
Add-Content “$TestCSVFile” $FinalStr
}
else
{
$ErrorOrNot=”Yes”
}

}

IF ($ErrorOrNot -eq “Yes”)
{
$TestText = “Please check to make sure a Domain Controller is reachable to execute Dynamic Pack.”
$SumVal = “”
$TestStatus=”Error executing Dynamic Pack”
}
else
{
IF ($AnyGap -eq “Yes”)
{
$TestStatus = “High”
$SumVal=””
$TestText = “Static DNS Records found in Domain Zones. Please ensure no DNS Static Records have been created for client computers other than servers that require a DNS Static record to be created in the Domain Zones. Static Record files are located at $StaticZoneAFile and $StaticZoneCNAMEFile”
}
IF ($AnyGap -eq “No”)
{
$TestStatus = “Passed”
$SumVal=””
$TestText = “No DNS Static Records were found in Domain Zones.”
}
}
$STR = $ADTestName +”,”+$TestStartTime+”,”+$TestStatus+”,”+$SumVal +”,”+$TestText

### Script Ends Here ###

Tip: Note that the script is smart enough to collect static DNS A and CNAME records from all the Active Directory domains specified in the DomList.txt and create two CSV files for each domain zone.

Once you have finished executing the script, a report will be generated to help you understand the status of static entries in each Active Directory domain as shown in the screenshot below:

Static DNS records

As you can see, the script collected static A and CNAME DNS records from the DNS Server for domain zones specified in the DomList.txt file and reported the number of static A and CNAME records found in each domain zone. Note that the static DNS entries with host name and its IP Address are saved in a CSV file under C:\Temp folder.

This script is part of PowerShell-based Dynamic Packs that ship with the Active Directory Health Profiler, which you can use to perform a complete health check of an Active Directory forest. There are 99 health checks included in the AD Health Profiler.

By using the above PowerShell script you can collect a list of DNS static A and CNAME records from the Active Directory domain zones. Since the script saves data (IP Address and host names) in separate CSV files for each domain. Once you have static DNS entries data with you, you can either remove the static DNS entries that are no longer needed or send the file to the domain owner for them to take actions accordingly.

Photo credit: Shutterstock

6 thoughts on “Querying and identifying static DNS records with PowerShell”

  1. how do i check multiple computers if that hostname exist on dns server using powershell and it will return to me True if the record exist and False if the record doesn’t exist in CSV.

  2. Hello Nirmal,
    Thank you for the post. This is exactly what I’m looking for. I’m having a bit of trouble running it and was hoping you could help. I’ve checked your pre-reques and the only difference is I’m running it from a 2019 DC.

    PS C:\Temp> .\DNSStaticEntries.ps1
    Import-Csv : Cannot validate argument on parameter ‘Path’. The argument is null or empty. Provide an argument that is
    not null or empty, and then try the command again.
    At C:\Temp\DNSStaticEntries.ps1:29 char:22
    + $PDCCSV = Import-CSV $PrefDCFile
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Import-Csv], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.ImportCsvCommand

    Get-DnsServerResourceRecord : Failed to get the zone information for name.changed on server Unknown.
    At C:\Temp\DNSStaticEntries.ps1:40 char:19
    + … cARecords = Get-DnsServerResourceRecord -ZoneName $ThisDomain -Comput …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (corporate.ncm:root/Microsoft/…rResourceRecord) [Get-DnsServerResourceRe
    cord], CimException
    + FullyQualifiedErrorId : WIN32 1722,Get-DnsServerResourceRecord

  3. Hello Matthew,
    Thank you for reading.

    I think there is a mistake in the script syntax. Someone one line got omitted. Can you please add below line right above “$PDCCSV = Import-CSV $PrefDCFile”

    $PrefDCFile = C:\Temp\None.Txt
    Add-Content $PrefDCFile “None”

    Hopefully it should work!

    I will get this script rectified.

    Thank You,
    Nirmal

  4. Hello Nirmal

    Thank you for your effort, but I think the syntax of the script has some issues and needs to review it.

    Import-Csv : Cannot validate argument on parameter ‘Path’. The argument is null or empty. Provide an argument that is not null or empty, and then try
    the command again.
    At line:38 char:22
    + $PDCCSV = Import-CSV $PDCListFile
    + ~~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Import-Csv], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.ImportCsvCommand

    Export-CSV : Could not find a part of the path
    ‘C:\ProgramData\DynamicPacksTechnologies\ADHealthProfiler\Data\DNSStaticRecordsTest\_StaticRecords_CNAMEmofa.com.CSV’.
    At line:78 char:23
    + $StaticCNAMERecords | Export-CSV $StaticZoneCNAMEFile -Append -NoTypeInfo
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OpenError: (:) [Export-Csv], DirectoryNotFoundException
    + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.ExportCsvCommand

    Import-Csv : Cannot validate argument on parameter ‘Path’. The argument is null or empty. Provide an argument that is not null or empty, and then try
    the command again.
    At line:38 char:22
    + $PDCCSV = Import-CSV $PDCListFile
    + ~~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Import-Csv], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.ImportCsvCommand

    Export-CSV : Could not find a part of the path
    ‘C:\ProgramData\DynamicPacksTechnologies\ADHealthProfiler\Data\DNSStaticRecordsTest\_StaticRecords_CNAME_msdcs.mofa.com.CSV’.
    At line:78 char:23
    + $StaticCNAMERecords | Export-CSV $StaticZoneCNAMEFile -Append -NoTypeInfo
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OpenError: (:) [Export-Csv], DirectoryNotFoundException
    + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.ExportCsvCommand

  5. Hello Nirmal,

    This script and explanation is missing variables and content.
    There is a $PDCListFile, but it is not declared and not filled. There is no explanation how this file should look like.
    Also, $HitWin2012DC and $CredInputforPS is not set at all, nor explained.

Leave a Comment

Your email address will not be published.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Scroll to Top