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

Envoyer Imprimer

Introduction

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()
{
 Param
 (
 [Parameter(Mandatory=$true)]
 [String] $Dn,
 
 [Parameter(Mandatory=$true)]
 [String] $NewDn,
 
 [Parameter(Mandatory=$true)]
 [String] $LdapServer,
 
 [Int] $LdapPort = 389
 )
 
 try
 {
 # 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)."
 }
 else
 {
 Write-Host "$($modifyResponse.ErrorMessage)"
 }
 }
 catch
 {
 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