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