Replicate a single object without repadmin.exe

How can I delete an active directory computer account object and instantly replicate the object deletion on another Domain Controller? - Let's find out!

What happens during "replication"?

Anyone with some exposure to AD DS might have come across repadmin - an extremely helpful command line utility possessing the power to make you master of replication, the driving force of Active Directory's distributed nature.

Replication is really simple - every now and then, a neighboring Domain Controller pokes you, you react by asking "what's new?" and the neighbor provides you with a ready list of LDAP operations it just performed on replicated data* in a specific partition you both host. You then replay these operations, test if the operations are consistent with the your own replica of the partition and voila, you just participated in Active Directory intra-site replication!

The modus operandi of Active Directory is to throttle replication traffic by grouping changes and contacting replication partners only on scheduled intervals. This is a sensible default behavior, but sometimes you really want to ensure that a change gets replicated right away. 

Repadmin solves this headache by accepting the /replsingleobj switch:

repadmin /replsingleobj in action

This would cause dc01 to replicate any changes to the object with the distinguished name "CN=someComputer,DC=lab,DC=iisreset,DC=me" from dc02

Distinguished Names

But what if you don't know or can't be certain of an objects DN?

According to the Active Directory Glossary, a "distinguished name" does not have to be the DN of an object, but can just as well be a globally unique object identifier. In the case of AD DS, this would be the objectGuid attribute of the object.

If the objectGuid of "CN=someComputer" is {73B2EA13-AE7E-45DF-BC01-F60F3C3433FE} we can replicate it like this:

This recently proved helpful when I tried to script my way out of deleting an existing computer account object in order to ensure that I could immediately join a new computer with an identical name to a domain with two Domain Controllers without it resulting in a naming conflict. Since the DN changes when the object is moved to the Deleted Objects container and I have no way of knowing whether the Domain Controller that didn't originate the deletion is going to replicate it right away or in 15 seconds - I can't be certain that the object is still identified by it's pre-deletion DN

So... PowerShell how?

Now, I love repadmin.exe, but wouldn't it be nice if we could implement the same behavior in PowerShell instead of having to rely on external applications?

Although powerful, repadmin.exe is really just a sample application, showcasing the underlying API through which any application can interface with Domain Controllers - including PowerShell. Fortunately, Microsoft has released detailed specifications of a large number of protocols, including those used in Active Directory, most notable in the comprehensive [MS-ADTS]: Active Directory Technical Specification document.

Knowing this, I reached out to my buddy Ryan Ries, and faster than the speed of a decaying synthetic hydrogen isotope, he found the piece of documentation needed and even constructed a small PoC! I love the interwebz.

You simply connect to the RootDSE on the replicating DC (dc01) and instruct it to perform a replicateSingleObject operation and pass a string containing the source DSA and object DNs as the argument:

$srcDC      = "CN=NTDS Settings,CN=dc02,CN=Servers,CN=SiteName,CN=Sites,CN=Configuration,DC=lab,DC=iisreset,DC=me"
$object     = "<GUID=73B2EA13-AE7E-45DF-BC01-F60F3C3433FE>"
$replString = $srcDC + ":" + $object
$dstRootDSE.Put("replicateSingleObject",$replString)

In the context of deleting a computer account object on dc02 and immediately replicating the deletion on dc01, I ended up with the following solution: 

# Specify the object, as well as source and destination DC names
$ComputerDN = "CN=laptop-01,OU=myComputers,DC=lab,DC=iisreset,DC=me" 
$dstDC = "dc01.lab.iisreset.me"
$srcDC = "dc02.lab.iisreset.me"

# Retrieve the unique identifier of the object and build a GUID-based DN
$ComputerDE = [ADSI]"LDAP://$srcDC/$ComputerDN" 
$ComputerGuid = [GUID]$ComputerDE.objectGUID.Value 
$ComputerDNGUID = "<GUID=$($ComputerGuid.ToString())>" 

# Delete the computer account object from it's current container
$ParentOU = [ADSI]$ComputerDE.Parent 
$ParentOU.Delete("Computer",($ComputerDN -split ",")[0]) 

# $dstRootDSE will perform the replication
$dstRootDSE = [ADSI]"LDAP://$dstDC/RootDSE" 
$srcRootDSE = [ADSI]"LDAP://$srcDC/RootDSE" 

# Get the DN of the source DC's DSA object (this is the "NTDS Settings" object in AD Sites and Services)
$sourceDSA = $srcRootDSE.dsServiceName.ToString() 

# Build the replication instruction
$replMsg = $sourceDSA + ":" + $ComputerDNGUID 

# Submit and fire!
$dstRootDSE.Put("replicateSingleObject",$replMsg) 
$dstRootDSE.SetInfo()

(This article was originally posted on Jan 25, 2014)