Jorge's Quest For Knowledge!

All You Need To Know About Identity And Security On-Premises And In The Cloud. It's Just Like An Addiction, The More You Have, The More You Want To Have!

(2010-10-24) Testing Active Directory Replication Latency/Convergence Through PowerShell

Posted by Jorge on 2010-10-24


UPDATE: the information below still applies. However, the script has been updated and is available through this post.

A few days ago I needed you test AD replication latency/convergence in a single AD domain AD forest environment. I had found Brandon Shell’s powershell script that was able to do this. His script only works in a single AD domain AD forest environment, so for me that was not a problem. However, a lot of people may have multiple AD domains in their AD forest, so I decided to adjust the script to also work in such an environment. This script does not leverage the Configuration partition to create an temporary object, but rather uses a certain domain partition. The data is then replicated to all DCs in that AD domain and the GCs in other AD domains, if any, in the same AD forest.

To use the script just copy the contents of the table below and put that in a script that could be called "Check-AD-Replication-Latency-Convergence.ps1", but this is of course not mandatory. In the explanations and examples I will use this name. Note that this script is not signed in any way by me, so you might need to adjust the PowerShell Execution Policy of the server where you want to execute this script. It is not possible to pass credentials through the script, so the account you are using should have the correct permissions to create (and delete afterwards) the temporary object in the specific container in AD (default used is ‘CN=Users,DC=<DOMAIN>,DC=<TLD>’) or you should execute the script from a PowerShell console window that was started with credentials that do have the correct permissions. In addition, the server where this script is executed must be able to access every DC (RWDC and RODC) in the same AD domain through LDAP (port 389) and all GCs in other AD domains through LDAP-GC (port 3268). So if your network is not fully routed or you have firewalls deployed between servers, you might need to figure out how to use the scripts. Last but not least, I just tested this script in a single AD domain AD forest with a few DCs (RWDCs and RODCs) and in a multiple AD domain AD forest, also with a few DCs. So I do not know how well this is going to perform in an environment with a lot of DCs. I f you are going to use this script, the only thing I would like to ask you is to give me feedback about it and your experiences. Thanks!

The script has two operational modes:

  • Normal Mode –> Check-AD-Replication-Latency-Convergence.ps1
  • Verbose Mode –> Check-AD-Replication-Latency-Convergence.ps1 -verbose

REMARK: ‘Verbose Mode’ will give you additional information about AD domains, DCs and GCs

After the script is started, you need to specify in which AD domain, the temporary object will be created:

  • Either specify the FQDN of an existing AD domain in the AD forest
    OR
  • Just press ENTER to use the current AD domain the server is joined to

REMARK: In either case the AD domain will be checked if it exists in the AD forest. If it exists, the script continues and if it does not exist, the script aborts.

After that, you need to specify on which RWDC from the previous AD domain, the temporary object will be created:

  • Either specify PDC to target the RWDC that hosts the PDC FSMO role
    OR
  • Either specify the FQDN of an existing RWDC in the AD domain
    OR
  • Just press ENTER to search for an RWDC in the AD domain
    • If an RWDC is located right away, then that RWDC will be used
    • If an RODC is located right away, then that cannot be used and the RWDC that hosts the PDC FSMO role will be targeted

REMARK: In all cases the RWDC will be checked if it exists in the AD domain. If it exists, the script continues and if it does not exist, the script aborts.

The code of the PowerShell script that does this is included below. Screen dumps are also included after the code sample.

UPDATE: I have also linked a file with the contents below to this blog post. Get it HERE.

# This script is based upon the script created by Brandon Shell [MVP-PoSH] # Source Of Original Script: http://bsonposh.com/archives/276 # # This script was adjusted by Jorge de Almeida Pinto [MVP-DS] # Source Of Adjusted Script: https://jorgequestforknowledge.wordpress.com/2010/10/24/testing-active-directory-replication-latency-convergence-through-powershell/ # # Some parameters/constants Param([switch]$verbose) # Start... Clear-Host Write-Host "*********************************************************" -ForeGroundColor Yellow Write-Host "* *" -ForeGroundColor Yellow Write-Host "* --> Test AD Replication Latency/Convergence <-- *" -ForeGroundColor Yellow Write-Host "* *" -ForeGroundColor Yellow Write-Host "* Written By: Brandon Shell [MVP-PoSH] *" -ForeGroundColor Yellow Write-Host "* (http://bsonposh.com/) *" -ForeGroundColor Yellow Write-Host "* *" -ForeGroundColor Yellow Write-Host "* Re-Written By: Jorge de Almeida Pinto [MVP-DS] *" -ForeGroundColor Yellow Write-Host "* (https://jorgequestforknowledge.wordpress.com/) *" -ForeGroundColor Yellow Write-Host "* *" -ForeGroundColor Yellow Write-Host "*********************************************************" -ForeGroundColor Yellow # Some constants $continue = $true $cleanupCanaryObject = $true # Get list of AD domains in AD forest $ThisADForest = [DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest() $ListOfADDomainsInADForest = $ThisADForest.Domains If ($verbose) { $TableOfADDomainsInADForest = @() Write-Host "" Write-Host "-------------------------------------------------------------------" -ForeGroundColor Cyan Write-Host "LIST OF DOMAINs IN THE AD FOREST..." -ForeGroundColor Cyan Write-Host "" Write-Host "ForestMode: "$ThisADForest.ForestMode ForEach ($Domain in $ListOfADDomainsInADForest) { $TableOfADDomainsInADForestObj = "" | Select Name,RootDomain,DomainMode,CurrentDomain $TableOfADDomainsInADForestObj.Name = $Domain.Name $TableOfADDomainsInADForestObj.RootDomain = "FALSE" If ($ThisADForest.RootDomain -like $Domain.Name) { $TableOfADDomainsInADForestObj.RootDomain = "TRUE" } $TableOfADDomainsInADForestObj.DomainMode = $Domain.DomainMode If ($Domain.Name -like $Env:USERDNSDOMAIN) { $TableOfADDomainsInADForestObj.CurrentDomain = "TRUE" } Else { $TableOfADDomainsInADForestObj.CurrentDomain = "FALSE" } $TableOfADDomainsInADForest += $TableOfADDomainsInADForestObj } $TableOfADDomainsInADForest | FT -AutoSize Write-Host " --> Found [$($ListOfADDomainsInADForest.count)] AD Domain(s) In AD Forest..." -ForeGroundColor Cyan } # Get list of GCs in AD forest $ListOfGCsInADForest = $ThisADForest.GlobalCatalogs If ($verbose) { $TableOfGCsInADForest = @() Write-Host "" Write-Host "-------------------------------------------------------------------" -ForeGroundColor Cyan Write-Host "LIST OF GCs IN THE AD FOREST '$ThisADForest'..." -ForeGroundColor Cyan ForEach ($GC in $ListOfGCsInADForest) { $TableOfGCsInADForestObj = "" | Select Name,Domain,SiteName $TableOfGCsInADForestObj.Name = $GC.Name $TableOfGCsInADForestObj.Domain = $GC.Domain $TableOfGCsInADForestObj.SiteName = $GC.SiteName $TableOfGCsInADForest += $TableOfGCsInADForestObj } $TableOfGCsInADForest | FT -AutoSize Write-Host " --> Found [$($ListOfGCsInADForest.count)] GC(s) In AD Forest..." -ForeGroundColor Cyan } Write-Host "" Write-Host "-------------------------------------------------------------------" -ForeGroundColor Blue # Determine which AD domain to use for the canary object. This does assume the correct AD permissions to create the object! Write-Host "In which AD Domain Should The Canary Object Be Created?" -ForeGroundColor Blue Write-Host "" $ADDomainToWriteTo = Read-Host "Please Provide FQDN Or Just Press ENTER For Current AD domain" # If no FQDN of an AD domain is specified, then use the local AD domain If ($ADDomainToWriteTo -eq "") { $ADDomainToWriteTo = $Env:USERDNSDOMAIN } # If a FQDN of an AD domain is specified, then check if it exists in this AD forest If ($ADDomainToWriteTo -ne "") { $ADdomainvalidity = $False ForEach ($Domain in $ListOfADDomainsInADForest) { If ($Domain.Name -like $ADDomainToWriteTo) { $ADdomainvalidity = $True } } Write-Host "" Write-Host "Checking existence of the specified AD domain '$ADDomainToWriteTo' in the AD forest..." -ForeGroundColor Blue If ($ADdomainvalidity -eq $True) { Write-Host "" Write-Host "The specified AD domain '$ADDomainToWriteTo' exists in the AD forest!" -ForeGroundColor Green Write-Host "" Write-Host "Continuing Script..." -ForeGroundColor Green Write-Host "" } If ($ADdomainvalidity -eq $False) { Write-Host "" Write-Host "The specified AD domain '$ADDomainToWriteTo' does not exist in the AD forest!" -ForeGroundColor Red Write-Host "" Write-Host "Please re-run the script and provide the FQDN of an AD domain that does exist in the AD forest" -ForeGroundColor Red Write-Host "" Write-Host "Aborting Script..." -ForeGroundColor Red Write-Host "" Break } } # Get list of DCs in AD domain $contextADDomainToWriteTo = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain",$ADDomainToWriteTo) $ListOfDCsInADDomain = [System.DirectoryServices.ActiveDirectory.DomainController]::findall($contextADDomainToWriteTo) If ($verbose) { $TableOfDCsInADDomain = @() Write-Host "" Write-Host "-------------------------------------------------------------------" -ForeGroundColor Cyan Write-Host "LIST OF DCs IN THE AD DOMAIN '$ADDomainToWriteTo'..." -ForeGroundColor Cyan ForEach ($DC in $ListOfDCsInADDomain) { $TableOfDCsInADDomainObj = "" | Select Name,Domain,GC,FSMO,SiteName,DStype $TableOfDCsInADDomainObj.Name = $DC.Name $TableOfDCsInADDomainObj.Domain = $ADDomainToWriteTo $TableOfDCsInADDomainObj.GC = "FALSE" ForEach ($GC in $ListOfGCsInADForest) { If ($DC.Name -like $GC.Name) { $TableOfDCsInADDomainObj.GC = "TRUE" } } If ($DC.Roles -ne $null) { ForEach ($FSMO In $DC.Roles) { If ($FSMO -eq "SchemaRole") {$FSMO = "SCH"} If ($FSMO -eq "NamingRole") {$FSMO = "DNM"} If ($FSMO -eq "PdcRole") {$FSMO = "PDC"} If ($FSMO -eq "RidRole") {$FSMO = "RID"} If ($FSMO -eq "InfrastructureRole") {$FSMO = "INF"} $TableOfDCsInADDomainObj.FSMO += $FSMO+"/" } $TableOfDCsInADDomainObj.FSMO = ($TableOfDCsInADDomainObj.FSMO).SubString(0,$TableOfDCsInADDomainObj.FSMO.Length-1) } Else { $TableOfDCsInADDomainObj.FSMO = "....." } $TableOfDCsInADDomainObj.SiteName = $DC.SiteName $ListOfRWDCsInADDomain = [System.DirectoryServices.ActiveDirectory.DomainController]::findall($contextADDomainToWriteTo) | ?{$_.OutboundConnections -ne $null} $DStype = "Read-Only" ForEach ($RWDC In $ListOfRWDCsInADDomain) { If ($RWDC.Name -like $DC.Name) { $DStype = "Read/Write" Break } } $TableOfDCsInADDomainObj.DStype = $DStype $TableOfDCsInADDomain += $TableOfDCsInADDomainObj } $TableOfDCsInADDomain | FT -AutoSize Write-Host " --> Found [$($ListOfDCsInADDomain.count)] DC(s) In AD Domain..." -ForeGroundColor Cyan } Write-Host "" Write-Host "Which DC In The AD Domain '$ADDomainToWriteTo' Should Be Used To Create The Object?" -ForeGroundColor Blue Write-Host "Possible Options Are:" -ForeGroundColor Blue Write-Host "* Specify PDC To Use The DC With The PDC FSMO Role" -ForeGroundColor Blue Write-Host "* Just Press Enter To Locate An RWDC" -ForeGroundColor Blue Write-Host "* Specify A Specific FQDN Of A RWDC" -ForeGroundColor Blue Write-Host "" $SourceRWDCInADDomain = Read-Host "Please Choose An Option" # If PDC was specified find the RWDC with the PDC FSMO role and use that If ($SourceRWDCInADDomain -eq "PDC") { $SourceRWDCInADDomainFQDN = ($ListOfADDomainsInADForest | %{$_.PdcRoleOwner} | ?{$_.Domain -like $ADDomainToWriteTo}).Name $SourceRWDCInADDomainDOMAIN = ($ListOfADDomainsInADForest | %{$_.PdcRoleOwner} | ?{$_.Domain -like $ADDomainToWriteTo}).Domain $SourceRWDCInADDomainSITE = ($ListOfADDomainsInADForest | %{$_.PdcRoleOwner} | ?{$_.Domain -like $ADDomainToWriteTo}).SiteName } # If nothing was specified locate an RWDC to use If ($SourceRWDCInADDomain -eq "") { # Locate just ONE DC (this could be a RWDC or RODC) $SourceRWDCInADDomainObjectONE = [System.DirectoryServices.ActiveDirectory.DomainController]::findone($contextADDomainToWriteTo) # Locate all RWDCs in the AD domain SourceRWDCInADDomainObjectALL = [System.DirectoryServices.ActiveDirectory.DomainController]::findall($contextADDomainToWriteTo) | ?{$_.OutboundConnections -ne $null} $UseRWDC = $False # Check if the single DC found is a RWDC or not by checking if it is in the list of RWDCs ForEach ($RWDC In $SourceRWDCInADDomainObjectALL) { If ($RWDC.Name -like $SourceRWDCInADDomainObjectONE.Name) { $UseRWDC = $True } } # If the single DC found is an RWDC, then use that one If ($UseRWDC -eq $True) { $SourceRWDCInADDomainFQDN = $SourceRWDCInADDomainObjectONE.Name $SourceRWDCInADDomainDOMAIN = $SourceRWDCInADDomainObjectONE.Domain $SourceRWDCInADDomainSITE = $SourceRWDCInADDomainObjectONE.SiteName } # If the single DC found is an RODC, then locate the RWDC with the PDC FSMO and use that one If ($UseRWDC -eq $False) { $SourceRWDCInADDomainFQDN = ($ListOfADDomainsInADForest | %{$_.PdcRoleOwner} | ?{$_.Domain -like $ADDomainToWriteTo}).Name $SourceRWDCInADDomainDOMAIN = ($ListOfADDomainsInADForest | %{$_.PdcRoleOwner} | ?{$_.Domain -like $ADDomainToWriteTo}).Domain $SourceRWDCInADDomainSITE = ($ListOfADDomainsInADForest | %{$_.PdcRoleOwner} | ?{$_.Domain -like $ADDomainToWriteTo}).SiteName } } # If a specific RWDC was specified then use that one If ($SourceRWDCInADDomain -ne "" -And $SourceRWDCInADDomain -ne "PDC") { $contextRWDCToWriteTo = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$SourceRWDCInADDomain) $SourceRWDCInADDomainObject = [System.DirectoryServices.ActiveDirectory.DomainController]::GetDomainController($contextRWDCToWriteTo) $SourceRWDCInADDomainFQDN = $SourceRWDCInADDomainObject.Name $SourceRWDCInADDomainDOMAIN = $SourceRWDCInADDomainObject.Domain $SourceRWDCInADDomainSITE = $SourceRWDCInADDomainObject.SiteName } # Check if the RWDC specified actually exists in the AD domain $RWDCvalidity = $False ForEach ($DC in $ListOfDCsInADDomain) { If ($DC.Name -like $SourceRWDCInADDomainFQDN) { $RWDCvalidity = $True } } Write-Host "" Write-Host "Checking existence of the specified RWDC '$SourceRWDCInADDomainFQDN' in the AD domain '$SourceRWDCInADDomainDOMAIN'..." -ForeGroundColor Blue If ($RWDCvalidity -eq $True) { Write-Host "" Write-Host "The specified RWDC '$SourceRWDCInADDomainFQDN' exists in the AD domain '$SourceRWDCInADDomainDOMAIN'!" -ForeGroundColor Green Write-Host "" Write-Host "Continuing Script..." -ForeGroundColor Green Write-Host "" } If ($RWDCvalidity -eq $False) { Write-Host "" Write-Host "The specified RWDC '$SourceRWDCInADDomainFQDN' does not exist in the AD domain '$SourceRWDCInADDomainDOMAIN'!" -ForeGroundColor Red Write-Host "" Write-Host "Please re-run the script and provide the FQDN of an RWDC within the AD domain '$SourceRWDCInADDomainDOMAIN' that does exist" -ForeGroundColor Red Write-Host "" Write-Host "Aborting Script..." -ForeGroundColor Red Write-Host "" Break } # Get list of DCs/GCs in AD domain/forest to which the canary object will replicate Write-Host "" Write-Host "-------------------------------------------------------------------" -ForeGroundColor Blue If ($verbose) { Write-Host "LIST OF DIRECTORY SERVERS THE CANARY OBJECT REPLICATES TO..." -ForeGroundColor Cyan } $TableOfDSServersA = @() $TableOfDSServersAObj = "" | Select Name,Domain,GC,SiteName $TableOfDSServersAObj.Name = ("$SourceRWDCInADDomainFQDN [SOURCE RWDC]").ToUpper() $TableOfDSServersAObj.Domain = $ADDomainToWriteTo $TableOfDSServersAObj.GC = "FALSE" ForEach ($GC in $ListOfGCsInADForest) { If ($SourceRWDCInADDomainFQDN -like $GC.Name) { $TableOfDSServersAObj.GC = "TRUE" } } $TableOfDSServersAObj.SiteName = $SourceRWDCInADDomainSITE $TableOfDSServersA += $TableOfDSServersAObj $TableOfDSServersB = @() $TableOfDSServersBObj = "" | Select Name,Domain,GC,SiteName,Time $TableOfDSServersBObj.Name = ("$SourceRWDCInADDomainFQDN [SOURCE RWDC]").ToUpper() $TableOfDSServersBObj.Domain = $ADDomainToWriteTo $TableOfDSServersBObj.GC = "FALSE" ForEach ($GC in $ListOfGCsInADForest) { If ($SourceRWDCInADDomainFQDN -like $GC.Name) { $TableOfDSServersBObj.GC = "TRUE" } } $TableOfDSServersBObj.SiteName = $SourceRWDCInADDomainSITE $TableOfDSServersBObj.Time = 0.00 $TableOfDSServersB += $TableOfDSServersBObj ForEach ($DC In $ListOfDCsInADDomain) { If(!($DC.Name -like $SourceRWDCInADDomainFQDN)) { $TableOfDSServersAObj = "" | Select Name,Domain,GC,SiteName $TableOfDSServersAObj.Name = $DC.Name $TableOfDSServersAObj.Domain = $DC.Domain $TableOfDSServersAObj.GC = "FALSE" ForEach ($GC in $ListOfGCsInADForest) { If ($DC.Name -like $GC.Name) { $TableOfDSServersAObj.GC = "TRUE" } } $TableOfDSServersAObj.SiteName = $DC.SiteName $TableOfDSServersA += $TableOfDSServersAObj } } ForEach ($GC In $ListOfGCsInADForest) { $ToBeAdded = $True ForEach ($DC In $ListOfDCsInADDomain) { If($DC.Name -like $GC.Name) { $ToBeAdded = $False } } If ($ToBeAdded) { $TableOfDSServersAObj = "" | Select Name,Domain,GC,SiteName $TableOfDSServersAObj.Name = $GC.Name $TableOfDSServersAObj.Domain = $GC.Domain $TableOfDSServersAObj.GC = "TRUE" $TableOfDSServersAObj.SiteName = $GC.SiteName $TableOfDSServersA += $TableOfDSServersAObj } } If ($verbose) { $TableOfDSServersA | FT -AutoSize Write-Host " --> Found [$($TableOfDSServersA.count)] Directory Server(s)..." -ForeGroundColor Cyan Write-Host "" Write-Host "-------------------------------------------------------------------" -ForeGroundColor Cyan } # Create the canary object on the RWDC $domainNCDN = (([ADSI]"LDAP://$SourceRWDCInADDomainFQDN/rootDSE").defaultNamingContext) $container = "CN=Users," + $domainNCDN $CanaryObjectName = "adReplTempObject" + (Get-Date -f yyyyMMddHHmmss) Write-Host "`n Creating Temp Contact Object...:" -ForeGroundColor Blue Write-Host " --> On RWDC.............: $SourceRWDCInADDomainFQDN" -ForeGroundColor Blue Write-Host " --> With Full Name......: $CanaryObjectName" -ForeGroundColor Blue Write-Host " --> With Description....: ...!!!...CANARY OBJECT TO TEST AD REPLICATION LATENCY/CONVERGENCE...!!!..." -ForeGroundColor Blue Write-Host " --> In AD Domain........: $ADDomainToWriteTo ($domainNCDN)" -ForeGroundColor Blue Write-Host " --> In Container........: $container" -ForeGroundColor Blue $CanaryObject = ([ADSI]"LDAP://$SourceRWDCInADDomainFQDN/$container").Create("contact","CN=$CanaryObjectName") $CanaryObject.Put("Description","...!!!...CANARY OBJECT TO TEST AD REPLICATION LATENCY/CONVERGENCE...!!!...") $CanaryObject.SetInfo() $CanaryObjectDN = $CanaryObject.distinguishedname #$CanaryObject = ([ADSI]"LDAP://$SourceRWDCInADDomainFQDN/$CanaryObjectDN") #$CanaryObject.Description = "...!!!...CANARY OBJECT TO TEST AD REPLICATION LATENCY/CONVERGENCE...!!!..." #$CanaryObject.CommitChanges() Write-Host "`n Temp Contact Object [$CanaryObjectDN] Created! `n" -ForeGroundColor Blue # Go through the process of checking each directory server to see if the canary object already has replicated to it $start = Get-Date $i = 0 Write-Host " --> Found [$($TableOfDSServersA.count)] Directory Server(s)..." -ForeGroundColor Blue Write-Host "" While($continue) { $i++ $oldpos = $host.UI.RawUI.CursorPosition Write-Host " =========== Check $i ===========" -ForeGroundColor Blue Write-Host "" Write-Host "REMARK: Each DC in the list below must be accessible through LDAP Over TCP (389)" Start-Sleep 1 $replicated = $true # For each directory server in the list perform a number of steps ForEach ($DSsrv in $TableOfDSServersA) { If ($DSsrv.Name -match $SourceRWDCInADDomainFQDN) { Write-Host " * Contacting DC In AD domain..." Write-Host " - $($DSsrv.Name.ToUpper()) Has Object [$CanaryObjectDN]" (" "*5) -ForeGroundColor Green continue } # If the directory server is a DC in the AD domain, then connect through LDAP (389) If ($DSsrv.Domain -like $ADDomainToWriteTo) { Write-Host " * Contacting DC In AD domain..." $objectPath = [ADSI]"LDAP://$($DSsrv.Name)/$CanaryObjectDN" } # If the directory server is a GC in another AD domain, then connect through LDAP-GC (3268) If (!($DSsrv.Domain -like $ADDomainToWriteTo)) { Write-Host " * Contacting GC In Other AD domain..." $objectPath = [ADSI]"GC://$($DSsrv.Name)/$CanaryObjectDN" } If ($objectPath.name) { # If the canary object already exists Write-Host " - $($DSsrv.Name.ToUpper()) Has Object [$CanaryObjectDN]" (" "*5) -ForeGroundColor Green If (!($TableOfDSServersB | ?{$_.Name -match $DSsrv.Name})) { $TableOfDSServersBobj = "" | Select Name,Domain,GC,SiteName,Time $TableOfDSServersBobj.Name = $DSsrv.Name $TableOfDSServersBObj.Domain = $DSsrv.Domain $TableOfDSServersBObj.GC = $DSsrv.GC $TableOfDSServersBObj.SiteName = $DSsrv.SiteName $TableOfDSServersBObj.Time = ("{0:n2}" -f ((Get-Date)-$start).TotalSeconds) $TableOfDSServersB += $TableOfDSServersBObj } } Else { # If the canary object does not yet exist Write-Host " ! $($DSsrv.Name.ToUpper()) Missing Object [$CanaryObjectDN]" -ForeGroundColor Red $replicated = $false } } If ($replicated) { $continue = $false } Else { $host.UI.RawUI.CursorPosition = $oldpos } } $end = Get-Date $duration = "{0:n2}" -f ($end.Subtract($start).TotalSeconds) Write-Host "`n Start : $start" -fore Yellow Write-Host " End : $end" -fore Yellow Write-Host " Duration : $duration Seconds" -fore Yellow # Cleanup the canary object on the RWDC If ($cleanupCanaryObject) { Write-Host "" Write-Host " Removing Test Contact Object... `n" -ForeGroundColor Blue ([ADSI]"LDAP://$SourceRWDCInADDomainFQDN/$container").Delete("contact","CN=$CanaryObjectName") Write-Host " Temp Contact Object [$CanaryObjectDN] Removed! `n" -ForeGroundColor Blue } # Output the table containing the information of each directory server and how long it took to reach that directory server after creation on the source RWDC $TableOfDSServersB | Sort-Object Time | FT -AutoSize

I will show examples of a single AD domain AD forest and of a multiple AD domain AD forest, but in both cases I will use verbose mode.

SINGLE AD DOMAIN AD FOREST

image

I just pressed ENTER to use the current AD domain.

image

I specified PDC to use the RWDC that hosts the PDC FSMO role

REMARK: This is a single AD domain AD forest environment so there is no impact, but if this was multiple AD domain AD forest environment, what was wrong with the configuration of one of the DCs in the forest root AD domain? (Hint: GC, Infrastructure FSMO) And of course WHY?

image

The temporary object was and the script is now checking it on all directory servers (DCs in AD domain and GCs in other AD domains in AD forest if any)

If a DC is marked green, then the temporary AD object has replicated to it and the script found the temporary AD object.

If a DC is marked red, then the temporary AD object has not yet replicated to it and the script did not find the temporary AD object.

image

When finished it shows the start time, the end time and the duration of time if tool before the temporary AD object reached all directory servers. It also removed the temporary AD object again to keep stuff clean.

This is a W2K8R2 AD forest that has change notification enabled on all AD site links. So after a change has occurred on a certain RWDC it will notify the very first replication partner after 15 seconds (=default) and each other replication partner with pauses of 3 seconds (=default).

SO looking at the example above the following happened:

  • RWDC ‘RFSRWDC1.ADCORP.LAB’ is where the creating of the temporary AD object originated;
  • RWDC ‘RFSRWDC1.ADCORP.LAB’ notified RWDC ‘RFSRWDC2.ADCORP.LAB’ after about 15 seconds and RWDC ‘RFSRWDC2.ADCORP.LAB’ inbound replicated the temporary AD object from RWDC ‘RFSRWDC1.ADCORP.LAB’;
  • About 3 seconds later RWDC ‘RFSRWDC1.ADCORP.LAB’ notified RODC ‘RFSRODC2.ADCORP.LAB’ and RODC ‘RFSRODC2.ADCORP.LAB’ inbound replicated the temporary AD object from RWDC ‘RFSRWDC1.ADCORP.LAB’;
  • About 15 seconds after RWDC ‘RFSRWDC2.ADCORP.LAB’ inbound replicated the temporary AD object, it notified RODC ‘RSCRODC2.ADCORP.LAB’ and RODC ‘RSCRODC2.ADCORP.LAB’ inbound replicated the temporary AD object from RWDC ‘RFSRWDC2.ADCORP.LAB’;
  • About 3 seconds later RWDC ‘RFSRWDC2.ADCORP.LAB’ notified RODC ‘RFSRODC1.ADCORP.LAB’ and RODC ‘RFSRODC1.ADCORP.LAB’ inbound replicated the temporary AD object from RWDC ‘RFSRWDC2.ADCORP.LAB’.

MULTIPLE AD DOMAIN AD FOREST

image

I just pressed ENTER to use the current AD domain.

image

I specified PDC to use the RWDC that hosts the PDC FSMO role

 

image

The temporary object was and the script is now checking it on all directory servers (DCs in AD domain and GCs in other AD domains in AD forest if any)

If a DC is marked green, then the temporary AD object has replicated to it and the script found the temporary AD object.

If a DC is marked red, then the temporary AD object has not yet replicated to it and the script did not find the temporary AD object.

image

When finished it shows the start time, the end time and the duration of time if tool before the temporary AD object reached all directory servers. It also removed the temporary AD object again to keep stuff clean.

This is a W2K8R2 AD forest that has change notification enabled on all AD site links. So after a change has occurred on a certain RWDC it will notify the very first replication partner after 15 seconds (=default) and each other replication partner with pauses of 3 seconds (=default).

SO looking at the example above the following happened:

  • RWDC ‘R1FSRWDC1.ADCORP.LAB’ is where the creating of the temporary AD object originated;
  • RWDC ‘R1FSRWDC1.ADCORP.LAB’ notified RODC ‘R1FSRODC1.ADCORP.LAB’ after about 15 seconds and RODC ‘R1FSRODC1.ADCORP.LAB’ inbound replicated the temporary AD object from RWDC ‘R1FSRWDC1.ADCORP.LAB’;
  • About 3 seconds later RWDC ‘R1FSRWDC1.ADCORP.LAB’ notified RWDC ‘C1FSRWDC1.CHLD.ADCORP.LAB’ and RWDC ‘C1FSRWDC1.CHLD.ADCORP.LAB’ inbound replicated the temporary AD object from RWDC ‘R1FSRWDC1.ADCORP.LAB’.

For more information on AD replication see:

Cheers,

Jorge

———————————————————————————————

* This posting is provided "AS IS" with no warranties and confers no rights!

* Always evaluate/test yourself before using/implementing this!

* DISCLAIMER: https://jorgequestforknowledge.wordpress.com/disclaimer/

———————————————————————————————

############### Jorge’s Quest For Knowledge #############

######### http://JorgeQuestForKnowledge.wordpress.com/ ########

———————————————————————————————

2 Responses to “(2010-10-24) Testing Active Directory Replication Latency/Convergence Through PowerShell”

  1. Cornell said

    I used the script and it work like a charm. My only question is that due to the number of OCONUS DC’s we have in our environment, there are instances when response time is very slow. Is there a way to prvent the script from looping after a certain number of attempts.

  2. […] About two years ago I wrote AD replication latency/convergence test script that can be found in this blog post. […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: