Posted On February 7, 2020

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

kimconnect 0 comments
blog.KimConnect.com >> Codes , Windows >> PowerShell: Remove an A-Host Record within Active Directory Integrated DNS Domain

Warning: this code is NOT ‘production ready’. Please review and test on DEV environments carefully before committing to use.

$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 *

Related Post

PowerShell: Get Try Catch Exception Type of a Function

# This function will return the exception type so that it could be specified on…

How To Format HTML Content For Email

Major email service providers such as Google Gmail and Microsoft Office 365 have been supporting…

PowerShell: DHCP Server Scope Options Editing

Occasionally, internal DNS server changes as machines are refreshed and/or decommissioned. DHCP servers should also…