Get and delete DNS A and PTR records via PowerShell

My Remote Desktop Session Host build process is now pretty slick. I can easily rebuild a lot of RDSH VMs very quickly. The process basically involved powering off the existing VM, deleting both it and its Active Directory account, and provisioning a new VM. However this causes a slight issue because the AD DNS record is left behind from the old VM, with the security to update it still assigned to the old VM. This means that if I change the allocated IP address for an RDSH server as part of the rebuild, the new VM doesn’t have permission to update the DNS A and PTR records for itself (security is done by AD SID, DNS just works on names/IP addresses).

So, time to use Get-DnsServerResourceRecord and Remove-DnsServerResourceRecord.

Doing the A record is easy:

$NodeToDelete = "rdsh01"
$DNSServer = ""
$ZoneName = ""
$NodeDNS = $null
$NodeDNS = Get-DnsServerResourceRecord -ZoneName $ZoneName -ComputerName $DNSServer -Node $NodeToDelete -RRType A -ErrorAction SilentlyContinue
if($NodeDNS -eq $null){
    Write-Host "No DNS record found"
} else {
    Remove-DnsServerResourceRecord -ZoneName $ZoneName -ComputerName $DNSServer -InputObject $NodeDNS -Force

So we try and get the DNS record we’re interested in. If the record is found, we delete it. I was originally doing this not using an -ErrorAction of “SilentlyContinue” but a “Stop”, which worked to a point but was inconsistent: If the DNS name I was trying to get had never existed (i.e. I made something up) it worked fine, but if I created an A record, ran the script to delete it, then tried the script again with the same DNS name to delete, the Get-DnsServerResourceRecord didn’t error. It didn’t return anything either, and hence why this is coded to use an if statement to check whether $NodeDNS is $null or not, rather than using a try/catch as was my original plan.

The PTR record is a little more fiddly. Now, getting PTR info via nslookup is easy:

C:\> nslookup


Not so with PowerShell… You have to specify the reverse lookup zone, and also give the right bit of the IP address in the right order.

For example, I want to find the name of the machine with IP address, and let’s assume my internet class B address range is

Get-DnsServerResourceRecord -ZoneName "" -ComputerName "" -Node "123.1" -RRtype Ptr

…nice. You can’t just pass it the full IP address as you can with nslookup. Oh no, we have to be a little more “creative”.

What I’ve ended up doing is using Get-DnsServerResourceRecord to look up the A record of the server to get its IP address, split this into an array – each element containing an octet of the address, then delete the PTR record and finally the A record.

param($NodeToDelete= "")
if($NodeToDelete-eq ""){
    Write-Error "You need to specify a name to delete" -Category NotSpecified -CategoryReason "Need a name to delete" -CategoryTargetName "Missing parameter" -CategoryTargetType "DNS name"

$DNSServer = ""
$ZoneName = ""
$ReverseZoneName = ""
$NodeARecord = $null
$NodePTRRecord = $null

Write-Host "Check for existing DNS record(s)"
$NodeARecord = Get-DnsServerResourceRecord -ZoneName $ZoneName -ComputerName $DNSServer -Node $NodeToDelete -RRType A -ErrorAction SilentlyContinue
if($NodeARecord -eq $null){
    Write-Host "No A record found"
} else {
    $IPAddress = $NodeARecord.RecordData.IPv4Address.IPAddressToString
    $IPAddressArray = $IPAddress.Split(".")
    $IPAddressFormatted = ($IPAddressArray[3]+"."+$IPAddressArray[2])
    $NodePTRRecord = Get-DnsServerResourceRecord -ZoneName $ReverseZoneName -ComputerName $DNSServer -Node $IPAddressFormatted -RRType Ptr -ErrorAction SilentlyContinue
    if($NodePTRRecord -eq $null){
        Write-Host "No PTR record found"
    } else {
        Remove-DnsServerResourceRecord -ZoneName $ReverseZoneName -ComputerName $DNSServer -InputObject $NodePTRRecord -Force
        Write-Host ("PTR gone: "+$IPAddressFormatted)
    Remove-DnsServerResourceRecord -ZoneName $ZoneName -ComputerName $DNSServer -InputObject $NodeARecord -Force
    Write-Host ("A gone: "+$NodeARecord.HostName)
This entry was posted in PowerShell, Scripting, Windows and tagged , , , , , , , , , , , , . Bookmark the permalink.

4 Responses to Get and delete DNS A and PTR records via PowerShell

  1. DanP. says:

    I think you have to account for ptr’s in any reverse zone before you declare there isn’t a ptr. I have yet to see an organization that is really strict on creating a reverse zone for every subnet.

    Test the last three octets, then two, then one.

    $reversezone = $ip -replace ‘^(\d+)\.(\d+)\.(\d+)\.(\d+)$’,’$3.$2.$’


  2. Alan says:

    Hi Guys, I Just created on Script using PtrDomainName as key to filter and delete Ptr records, I think is better becouse we don´t need to searh for Ip address in the code…

    In My case I deleted all HostNames starting with 12 numbers, that is garbage in my DNS.
    But you can adapt to Hostname geting by the main Zone.


    $records=Get-DnsServerResourceRecord -ZoneName “$zone” -ComputerName $DNSServer |
    Where-Object {$_.RecordType -eq “$recordtype” -and $_.RecordData.PtrDomainName.Substring(0,12) -match “^[0-9]*$”}

    Foreach ($record in $records)
    # Remove the DNS record by filtering

    Remove-DnsServerResourceRecord -ZoneName $zone -ComputerName $DNSServer -Force -RRType “$recordtype” -Name $record.HostName

    Write-Host (“[{0}] deleted record name is : $hostadi ($info)” -f (Get-Date))
    (“[{0}] delete record name: $hostadi ($info)” -f (Get-Date)) | out-file “E:\LimpaDNS\LimpaPTR.txt” -Append
    Write-Host (“[{0}] Cannot delete the record: $hostadi ($info)” -f (Get-Date))
    (“[{0}] Cannot delete the record name: $hostadi ($info)” -f (Get-Date)) | out-file “E:\LimpaDNS\LimpaPTR.txt” -Append


  3. curropar says:


    Inspired in these two (the original and the one in the comments), I just came across with this one. Adventages:
    – Environment agnostic: it finds the DNS zones and a DNS server by itself.
    – Use of Resolve-DnsName to simplify the obtention of the properties of the record (I really don’t understand why the output Get-DnsServerResourceRecord is so “complex”).

    – Not that I’ve controlled it much, just that the A and the PTR records are for the same machine.
    – Use of Resolve-DnsName, so at least 2012 R2 is required, but that should not be a problem by now.

    The script:

    $ListOfHosts = @("Server1","Server2","Server3")
    foreach ($HostToDelete in $ListOfHosts){
    $DNSDirectZone = $env:userdnsdomain
    $DNSServer = $env:logonserver -replace '\\',''

    $DNSARecord = Resolve-DnsName $HostToDelete
    $AHostName = $DNSARecord.Name -replace $DNSDirectZone,"" -replace "\.$",""

    $DNSPtrRecord = Resolve-DnsName $DNSARecord.IPAddress
    $DNSReverseZone = (Get-DnsServerZone -ComputerName $DNSServer | ?{$DNSPtrRecord.Name -match $_.ZoneName -and $_.IsDsIntegrated -eq $true}).ZoneName

    $PtrHostName = $DNSARecord.IPAddress -split "\."
    $PtrHostName = $PtrHostName -join "." -replace $DNSReverseZoneSuffix,"" -replace "\.$",""

    if ($DNSPtrRecord.NameHost -eq $DNSARecord.Name) {
    Remove-DnsServerResourceRecord -ComputerName $DNSServer -ZoneName $DNSReverseZone -Name $PtrHostName -RRType Ptr -Confirm:$false -Force

    Remove-DnsServerResourceRecord -ComputerName $DNSServer -ZoneName $DNSDirectZone -Name $AHostName -RRType A -Confirm:$false -Force


  4. Tom says:

    Hi curropar.
    Thanks for your combined script.
    I’ve fixed one line in it though:

    $DNSReverseZone = (Get-DnsServerZone -ComputerName $DNSServer | ?{$DNSPtrRecord.Name -match $_.ZoneName -and $_.IsDsIntegrated -eq $true}).ZoneName

    $DNSReverseZone = (Get-DnsServerZone -ComputerName $DNSServer | Where-Object {($DNSPtrRecord.Name.Substring($DNSPtrRecord.Name.Split(‘.’)[0].Length+1,$DNSPtrRecord.Name.Length-$DNSPtrRecord.Name.Split(‘.’)[0].Length-1) -eq $_.Zonename) -and ($_.IsDsIntegrated -eq $true)}).ZoneName

    This is better because “-match” could return more than one value.



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.