PowerShell: Remove an A-Host Record within Active Directory Integrated DNS Domain

$aRecord='testwindows'
$zone='intranet.kimconnect.net'
$adminUsername='intranet\TESTADMIN'
$adminPassword='PASSWORDHERE' # Testing
$dnsServer='DNSSERVER'

function removeHostRecordOnDns{
  param (
    $dnsServer,
    $record,
    $zone,
    $adminCred
    )

    if($record -eq $null){
        Write-Warning "Missing record parameter"
        return $false
    }
 
    $session=new-pssession $dnsServer -Credential $adminCred
 
    # This function is to be invoked on a DNS Server
    function removeARecord($record,$zone){
        # Clear variables in preparations for the process
        $aRecord = $null
        $ptrRecord = $null       
 
        # This only works if reverse lookup zones are constructed with respects to 'classful' ip addressing
        function constructZoneName($ip){            
            $ipFragments=$ip.split('.')
            $zoneSuffix='.in-addr.arpa'
 
            function getClassfulMask($ip){
                $regexIpv4 = "\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b"
                if($ip -match $regexIpv4){
                    $firstOctet=($ip.split('.'))[0]
                    $class=switch ($firstOctet){
                        ({$firstOctet -lt 128}){@{'class'='A';'cidr'='8';'mask'='255.0.0.0'};Break}
                        ({$firstOctet -lt 192}){@{'class'='B';'cidr'='16';'mask'='255.255.0.0'};Break}
                        ({$firstOctet -lt 224}){@{'class'='C';'cidr'='24';'mask'='255.255.255.0'};Break}
                        ({$firstOctet -lt 240}){@{'class'='D';'cidr'='undefined';'mask'='undefined'};Break}
                        default {@{'class'='E';'cidr'='undefined';'mask'='undefined'}}
                    }
                    return $class
                }
                else{
                    write-warning "Value $ip is not an IPv4 Address";
                    return $false
                }
            }
 
            function reverseOctets($ipFragment){
                [array]$octets=$ipFragment.Split('.')
                $reverse=[array]::Reverse($octets)
                return $reverse
            }
 
            $ipClass=(getClassfulMask $ip).class
            $zoneName=switch ($ipClass){
                'A' {$ipFragments[0]+$zoneSuffix;break}
                'B' {$ipFragments[1]+'.'+$ipFragments[0]+$zoneSuffix;break}
                'C' {$ipFragments[2]+'.'+$ipFragments[1]+'.'+$ipFragments[0]+$zoneSuffix;break}
                'D' {$ipFragments[3]+'.'+$ipFragments[2]+'.'+$ipFragments[1]+'.'+$ipFragments[0]+$zoneSuffix;break}
                'E' {$ipFragments[3]+'.'+$ipFragments[2]+'.'+$ipFragments[1]+'.'+$ipFragments[0]+$zoneSuffix;break}
            }
            return $zoneName
        }
 
        function confirmation($content,$testValue="I confirm",$maxAttempts=3){
        $confirmed=$false;
        $attempts=0;        
        $content|write-host
        write-host "Please review this content for accuracy.`r`n"
        while ($attempts -le $maxAttempts){
            if($attempts++ -ge $maxAttempts){
                write-host "A maximum number of attempts have reached. No confirmations received!`r`n"
                break;
                }
            $userInput = Read-Host -Prompt "Please type in this value => $testValue <= to confirm";
            if ($userInput.ToLower() -ne $testValue.ToLower()){
                cls;
                $content|write-host
                write-host "Attempt number $attempts of $maxAttempts`: $userInput does not match $testValue. Try again..`r`n"
                }else{
                    $confirmed=$true;
                    write-host "Confirmed!`r`n";
                    break;
                    }
            }
        return $confirmed;
    }
 
        Write-Host "Check for existing DNS record(s)..."
        $aRecord = Get-DnsServerResourceRecord -ZoneName $zone -Node $record -RRType A -ErrorAction SilentlyContinue
        if($aRecord -eq $null){
            Write-Host "No A-host records found"
            }
        else {
            # Purge Reverse pointer record(s) first
            $ipAddress=$aRecord.RecordData.IPv4Address.IPAddressToString
            $reverseLookupZones=(Get-DnsServerZone|?{$_.IsReverseLookupZone -eq $true}).ZoneName
            $reverseIp=.{$fragments=$ipAddress.split('.');
                        [array]::Reverse($fragments)
                        return $fragments -join '.'
                        }
            $ptrMatch=.{foreach ($x in $reverseLookupZones){
                            $numericalFragment=.{[void]($x -match '(\d{1,3}\.{0,1}){1,3}(?!\w)');$matches[0]}
                            if($matches){$matches=$null}
                            if($numericalFragment -gt 0){
                                $ptrNode=.{$match=$reverseIp -like "*$numericalFragment";
                                            if($match){
                                                $lengthDifference=$reverseIp.length-$numericalFragment.length;
                                                return $reverseIp[0..$($lengthDifference-2)] -join ''
                                                }
                                            }                            
                                if($ptrNode){                                    
                                    $y=Get-DnsServerResourceRecord -ZoneName $x -Node $ptrNode -RRType Ptr -ErrorAction SilentlyContinue
                                    if($y){
                                        write-host "PTR record $ptrNode is found in zone $x"
                                        return @{'zoneName'=$x;'ptrRecord'=$y}
                                        }
                                    }                                
                                }
                              }
                            }            
            if($ptrMatch -eq $null){
                Write-Host "No PTR records found"
                }
            else {
                $ptrRecord=$ptrMatch['ptrRecord']
                $ptrZoneName=$ptrMatch['zoneName']
                $removeReverseZoneRecordCommand="Remove-DnsServerResourceRecord -ZoneName $ptrZoneName -InputObject `$ptrRecord -Force"
                #write-host $removeReverseZoneRecordCommand
                $confirm=confirmation -content $removeReverseZoneRecordCommand
                if($confirm){
                    Invoke-Expression $removeReverseZoneRecordCommand
                    Write-Host "PTR record removed: reverse record $ptrRecord, IP $ipAddress, Zone $ptrZoneName`n`n`n`n"
                    }
                else{write-host "No confirmations received. Reverse record $ptrRecord was NOT removed from zone $ptrZoneName"}
            }
            # Purge A-host record
            $removeHostRecord="Remove-DnsServerResourceRecord -ZoneName $zone -InputObject `$aRecord -Force"
            $confirm=confirmation -content $removeHostRecord
            if($confirm){
                invoke-expression $removeHostRecord
                Write-Host ("A-record $record has been successfully removed from zone $zone")
                }
            else{write-host "No confirmations received. $record was NOT removed from zone $zone"}
            }
    }
 
    invoke-command -session $session -ScriptBlock{
        param($removeARecord,$record,$zone)
        [ScriptBlock]::Create($removeARecord).invoke($record,$zone)
        } -Args ${function:removeARecord},$record,$zone
    Remove-PSSession $session
}

if($adminUsername -and $adminPassword){$adminCred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $adminUsername,$(ConvertTo-SecureString $adminPassword -AsPlainText -Force)}
if(!$adminCred){$adminCred=get-credential}
if(!$dnsServer){$dnsServer=[regex]::match($env:LOGONSERVER,'\\\\(.*)').groups[1].value}
removeHostRecordOnDns $dnsServer $record $zone $adminCred
# Another method of resolving the DNS Reverse Zone
$reverseLookupZones = (Get-DnsServerZone -ComputerName $dnsServer | Where-Object {($ptrRecord.Name.Substring($ptrRecord.Name.Split('.')[0].Length+1,$ptrRecord.Name.Length-$ptrRecord.Name.Split('.')[0].Length-1) -eq $_.Zonename) -and ($_.IsDsIntegrated -eq $true)}).ZoneName
# The script above has rendered this one outdated

# Manual entry variable
$aRecord="DECOMMISSIONEDSHERVER"

# Autogen variable
import-module ActiveDirectory
$dnsServers=(Get-ADDomainController -Filter *).Name

function checkOneDnsServer{
param(
$record,
$dnsServer
)
$resolve=Resolve-DnsName -Name $record -Server $dnsServer -QuickTimeout -ea SilentlyContinue
if($resolve.Name -ne $null){
write-host "$dnsServer has records of $record as $($resolve.IPAddress)`: YES!`r`n"
return $true
}else{
write-host "$dnsServer has records of $record`: NO!`r`n";
return $false
}
}

# Manual DNS record removal
function removeDnsARecord{
param(
[string]$record,
$dnsServers=(Get-ADDomainController -Filter *).Name
)
$dnsServers|%{
$recordExists=checkOneDnsServer -record $record -dnsServer $_;
if(!$recordExists){
write-host "Removing record $record from DNS server $_...";
try{
invoke-command -ComputerName $_ -scriptblock {
param($x)
Remove-DnsServerResourceRecord -ZoneName $env:USERDNSDOMAIN -RRType "A" -Name $x -Force -Confirm:$false -ea SilentlyContinue
} -args $record
}catch{
write-host $Error
write-host "Unable to remove record $record from DNS server $_...";
}
}
}
}

# Perform DNS Record removal - caveat emptor!
#removeDnsARecord -record $aRecord -dnsServers $dnsServers

function checkAllDnsServers{
param(
$record,
$dnsServers=(Get-ADDomainController -Filter *).Name
)
$recordExists=0;
$recordNotExists=0;
$serversCount=$dnsServers.count
$dnsServers|%{
$resolve=Resolve-DnsName -Name $record -Server $_ -QuickTimeout -ea SilentlyContinue
$result=if($resolve.Name -ne $null){
write-host "$_ has records of $record as $($resolve.IPAddress)`: Yes!`r`n" -NoNewline;
$recordExists++;
}else{
write-host "$_ has records of $record`: No!`r`n" -NoNewline;
$recordNotExists++;
}
}

if ($recordExists){
write-host "There are $recordExists of $serverCount DNS servers with record of $record.";
return $True
}else{
write-host "There are no entries of $record on all $serversCount DNS servers.";
return $False
}
}

# Validation
checkAllDnsServers -dnsServers $dnsServers -record $aRecord

Leave a Reply

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