Reanimate Active Directory tombstone objects with PowerShell (using System.DirectoryServices.Protocols)

Envoyer Imprimer


During a couple of days, I was searching a way for reanimating tombstone objects using only the Active Directory module for Windows PowerShell and, for some reasons, I did not want to use any additional Quest cmdlets or SDM Software cmdlets.



Retrieve tombstone objects with PowerShell

To get all tombstone objects within a domain, you just have to type the command: get-adobject -filter 'isDeleted -eq $true' –IncludeDeletedObjects


The option –IncludeDeletedObjects permits to explore the hidden container “cn=deleted objects” of the domain. The filter 'isDeleted -eq $true' will focus on tombstone objects.

As Reminder, the major difference between a tombstone object and a standard object is the attribute isDeleted (set to true for tombstone objects) and the parent container (a tombstone object is always placed into the container deleted objects).

Remark: the parent container of an object is partially defined by its distinguishedName.



Reanimate tombstone objects with PowerShell

Now we want to simply reanimate a specific tombstone object by changing its parent container and its isDeleted attribute but we are not able to manage them with the set-adobject cmdlet. There is no -IncludeDeletedObjects option for it and the tombstone object is just “not found”.


Finally, I have found a .Net function (Resurrecting tombstones in Active Directory or ADAM) that I have converted to PowerShell and it is working fine from my side.

function Reanimate-Object()
 [String] $Dn,
 [String] $NewDn,
 [String] $LdapServer,
 [Int] $LdapPort = 389
 # Delete the attribute isDeleted
 $LdapAttrIsDeleted = New-Object -TypeName System.DirectoryServices.Protocols.DirectoryAttributeModification
 $LdapAttrIsDeleted.Name = "isdeleted"
 $LdapAttrIsDeleted.Operation = "Delete"
 # Replace the attribute distinguishedName
 $LdapAttrDn = New-Object -TypeName System.DirectoryServices.Protocols.DirectoryAttributeModification
 $LdapAttrDn.Name ="distinguishedname"
 $LdapAttrDn.Add($NewDn) | Out-Null
 $LdapAttrDn.Operation = "Replace"
 # Create modify request
 $LdapModifyRequest = New-Object -TypeName System.DirectoryServices.Protocols.ModifyRequest($Dn,@($LdapAttrIsDeleted,$LdapAttrDn))
 $LdapModifyRequest.Controls.Add((New-Object System.DirectoryServices.Protocols.ShowDeletedControl)) | Out-Null
 # Establish connection to Active Directory
 $LdapConnection = new-object System.DirectoryServices.Protocols.LdapConnection(new-object System.DirectoryServices.Protocols.LdapDirectoryIdentifier($LdapServer))
 # Send modify request
 [System.DirectoryServices.Protocols.DirectoryResponse]$modifyResponse = $ldapConnection.SendRequest($ldapModifyRequest)
 # Return result
 if ( $modifyResponse.ResultCode -eq "Success" )
 Write-Host "object reanimated as $($NewDN)."
 Write-Host "$($modifyResponse.ErrorMessage)"
 Write-Host "$($_.Exception.Message)"


To use this function, you just have to:

  • Load the .Net assemblies and the Active Directory module for Windows Powershell.
  • Retrieve the specified tombstone object.
  • Defined the new distinguishedName attribute based on the actual CN and lastKnownParent attribute.
  • Call the function with the correct parameters.

# Load Active Directory Module for Windows PowerShell
Import-Module ActiveDirectory
# Load assemblies
[System.Reflection.assembly]::LoadWithPartialName("system.directoryservices") | Out-Null
[System.Reflection.assembly]::LoadWithPartialName("system.directoryservices.protocols") | Out-Null
# Retrieve deleted object
$ADObject = Get-ADObject -Filter 'sAMAccountName -eq "aaugagneur"' -IncludeDeletedObjects -Property *
# Define regular expression to capture CN attribute
[regex] $RegexDnTombstones = "(?<CN>CN=.*)\\0ADEL.*"
# Define new distinguishedName attribute based on captured CN attribute and lastKnownParent attribute
$NewDn = (($RegexDnTombstones.Match($ADObject.distinguishedName)).Groups["CN"].value)+","+($ADObject.lastKnownParent)
# Call function
Reanimate-Object -Dn $ADObject.distinguishedName -NewDn $NewDn -LdapServer "localhost"



If you want to explore deeper S.DS.P you can check another example from Microsoft Script Center: Using System.DirectoryServices.Protocols from Powershell

Mise à jour le Mardi, 17 Juillet 2012 07:16