Skip to content

Instantly share code, notes, and snippets.

@bentman
Last active June 20, 2024 09:23
Show Gist options
  • Save bentman/7c0ff8f837b97dc0ef562a01e9661ce5 to your computer and use it in GitHub Desktop.
Save bentman/7c0ff8f837b97dc0ef562a01e9661ce5 to your computer and use it in GitHub Desktop.
function Wait-UntilAdComputerDeleted {
<#
.SYNOPSIS
Waits until a specified computer object is deleted from all domain controllers.
.DESCRIPTION
This function checks the deletion status of a specified computer object across all discovered domain controllers. It waits until the object is confirmed deleted on all domain controllers or identifies any inaccessible controllers after a specified number of failures.
.PARAMETER computerName
The name of the computer object to check for deletion. Required.
.PARAMETER sleepInterval
The number of seconds to wait between checks. Default is 5 seconds.
.PARAMETER failureThreshold
The number of failures before a domain controller is considered inaccessible. Default is 5 failures.
.EXAMPLE
Wait-UntilAdComputerDeleted -computerName "Computer1"
.EXAMPLE
Wait-UntilAdComputerDeleted -computerName "Computer1" -sleepInterval 10 -failureThreshold 3
#>
param (
[Parameter(Mandatory = $true)] [string]$computerName,
[Parameter()] [int]$sleepInterval = 5, # Default sleep interval of 5 seconds
[Parameter()] [int]$failureThreshold = 5 # Number of failures before considering a DC as inaccessible
)
# Import the Active Directory module
try { Import-Module ActiveDirectory -ErrorAction Stop }
catch { Write-Output "Error importing Active Directory module: $($_.Exception.Message)"; return }
# Get the distinguished name of the computer object
try { $computer = Get-ADComputer -Identity $computerName -ErrorAction Stop }
catch { Write-Output "Error retrieving computer object '$computerName': $($_.Exception.Message)"; return }
if ($null -eq $computer) { Write-Output "Computer object '$computerName' not found in Active Directory."; return }
$objectDN = $computer.DistinguishedName
# Dynamically discover domain controllers
try { $domainControllers = (Get-ADDomainController -Discover -Service PrimaryDC).HostName }
catch { Write-Output "Error retrieving domain controllers: $($_.Exception.Message)"; return }
$failureCount = @{}; $inaccessibleDCs = @()
foreach ($dc in $domainControllers) { $failureCount[$dc] = 0 }
do {
$remainingDCs = @($domainControllers | Where-Object { $inaccessibleDCs -notcontains $_ })
foreach ($dc in $remainingDCs) {
try {
$replicationMetadata = Get-ADReplicationAttributeMetadata -Object $objectDN -Server $dc -Properties "isDeleted" -ErrorAction Stop
if ($null -eq $replicationMetadata -or $replicationMetadata.AttributeMetaData.isDeleted -ne $true) { Write-Output "Object $objectDN is not deleted on $dc." }
else {
Write-Output "Object $objectDN is confirmed deleted on $dc."
$domainControllers = $domainControllers -ne $dc # Remove the DC from future checks
}
$failureCount[$dc] = 0 # Reset failure count on successful contact
}
catch {
Write-Output "Error checking deletion status on $($dc): $($_.Exception.Message)"
$failureCount[$dc]++
if ($failureCount[$dc] -ge $failureThreshold) { Write-Output "Marking $dc as inaccessible after $failureThreshold failures."; $inaccessibleDCs += $dc }
}
}
if ($domainControllers.Count -gt 0) {
Write-Output "$($domainControllers.Count) domain controller(s) remaining. Waiting for $sleepInterval seconds before rechecking..."
Start-Sleep -Seconds $sleepInterval
}
}
while ($domainControllers.Count -gt 0)
if ($inaccessibleDCs.Count -gt 0) { Write-Output "The following domain controller(s) were inaccessible:"; $inaccessibleDCs | ForEach-Object { Write-Output "- $_" } }
if ($domainControllers.Count -eq 0) {
if ($inaccessibleDCs.Count -gt 0) { Write-Output "Object $objectDN is deleted on all accessible domain controllers, but some were inaccessible." }
else { Write-Output "Object $objectDN is deleted on all domain controllers." }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment