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!

(2014-09-17) Finding Conflicting Objects In Your AD

Posted by Jorge on 2014-09-17


You might have seen it in your own AD or in somebody else’s AD, conflicting/duplicate objects. Those objects are exactly same objects that were created on different RWDCs at nearly the same time. After replication kicks and those conflicting/duplicate objects replicate to other RWDCs, AD replication needs to apply its own conflict resolution mechanism to ensure every object is and remains unique.

So, let’s say you create the object "CN=TestObject,OU=MyOU,DC=DOMAIN,DC=COM" on 2 different RWDCs at (nearly) the same time. After AD replication has converged you will see the following objects:

  1. "CN=TestObjectACNF:4862d44c-76ab-41b7-bac8-8682900e661b,OU=MyOU,DC=DOMAIN,DC=COM"
  2. "CN=TestObject,OU=MyOU,DC=DOMAIN,DC=COM"

[1] is the first created object and [2] was the last created object. The last object created is always the one that does not have ACNF:<objectGUID> in its CN/RDN. AD puts ACNF:<objectGUID> in the CN/RDN telling us it is a CONflict object and making sure it is unique in the container where also the other object is in.

The following PowerShell script helps you finding these objects in your AD forest. Based upon the information of the objects you need to determine yourself which of the two objects should be removed and which one can remain in AD.

# Clear The Screen Clear-Host # Checking Number Of Arguments $numArgs = $args.count $arg0 = $args[0] # Discovering A GC Retrieving Its DNS HostName $dnsHostNameGC = (Get-ADDomainController -Service GlobalCatalog -Discover:$true).HostName[0] $gcHostPort = $dnsHostNameGC + ":3268" $dsContextDC = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$dnsHostNameGC) $dc = [System.DirectoryServices.ActiveDirectory.DomainController]::GetDomainController($dsContextDC) # General Execution Of Script If ($numArgs -eq 0) { $listOfConflictingObjects = Get-ADObject -server $gcHostPort -LDAPFilter '(name=*CNF:*)' } If ($numArgs -eq 1) { If ($arg0.ToLower() -eq "computer") { $listOfConflictingObjects = Get-ADComputer -server $gcHostPort -LDAPFilter '(name=*CNF:*)' -Properties pwdLastSet } If ($arg0.ToLower() -eq "user") { $listOfConflictingObjects = Get-ADUser -server $gcHostPort -LDAPFilter '(name=*CNF:*)' -Properties pwdLastSet } } If ($listOfConflictingObjects -ne $null) { $listOfDuplicates = @() $listOfConflictingObjects | %{ $objCNF = $_ $dnCNFobj = $objCNF.DistinguishedName $classCNFobj = $_.ObjectClass $guidCNFobj = $_.ObjectGUID If ($numArgs -eq 1 -And ($arg0.ToLower() -eq "computer" -Or $arg0.ToLower() -eq "user")) { $sAMAccountCNFobj = $_.SamAccountName $pwdLastSetCNFobj = $_.pwdLastSet If ($pwdLastSetCNFobj -ne $null){ $pwdLastSetCNFobj = Get-Date -Date ([DateTime]::FromFileTime([Int64]::Parse($pwdLastSetCNFobj))) -Format "yyyy-MM-dd HH:mm:ss" } Else { $pwdLastSetCNFobj = "---" } } $objCNFMetadata = $dc.GetReplicationMetadata($dnCNFobj) $objCNFOrigSrv = $objCNFMetadata | %{($_.objectclass).OriginatingServer} $objCNFOrigTime = $objCNFMetadata | %{($_.objectclass).LastOriginatingChangeTime} $dnORGobj = $dnCNFobj.Substring(0,$dnCNFobj.IndexOf("\")) + $dnCNFobj.Substring($dnCNFobj.IndexOf(",")) If ($numArgs -eq 0) { $objORG = Get-ADObject -server $gcHostPort -Identity $dnORGobj } If ($numArgs -eq 1) { If ($arg0.ToLower() -eq "computer") { $objORG = Get-ADComputer -server $gcHostPort -Identity $dnORGobj -Properties pwdLastSet } If ($arg0.ToLower() -eq "user") { $objORG = Get-ADUser -server $gcHostPort -Identity $dnORGobj -Properties pwdLastSet } } $dnORGobj = $null $classORGobj = $null $guidORGobj = $null $sAMAccountORGobj = $null $pwdLastSetORGobj = $null $objORGMetadata = $null If ($objORG -ne $null) { $dnORGobj = $objORG.DistinguishedName $classORGobj = $objORG.ObjectClass $guidORGobj = $objORG.ObjectGUID If ($numArgs -eq 1 -And ($arg0.ToLower() -eq "computer" -Or $arg0.ToLower() -eq "user")) { $sAMAccountORGobj = $objORG.SamAccountName $pwdLastSetORGobj = $objORG.pwdLastSet If ($pwdLastSetORGobj -ne $null){ $pwdLastSetORGobj = Get-Date -Date ([DateTime]::FromFileTime([Int64]::Parse($pwdLastSetORGobj))) -Format "yyyy-MM-dd HH:mm:ss" } Else { $pwdLastSetORGobj = "---" } } $objORGMetadata = $dc.GetReplicationMetadata($dnORGobj) $objORGOrigSrv = $objORGMetadata | %{($_.objectclass).OriginatingServer} $objORGOrigTime = $objORGMetadata | %{($_.objectclass).LastOriginatingChangeTime} } Else { $dnORGobj = "Does Not Exit" $classORGobj = "Does Not Exit" $guidORGobj = "Does Not Exit" If ($numArgs -eq 1 -And ($arg0.ToLower() -eq "computer" -Or $arg0.ToLower() -eq "user")) { $sAMAccountORGobj = "Does Not Exit" $pwdLastSetORGobj = "Does Not Exit" } $objORGOrigSrv = "Does Not Exit" $objORGOrigTime = "Does Not Exit" } If ($numArgs -eq 0) { $adObj = "" | Select "> > >DN (CNF)..........","objectClass (CNF)......","objectGUID (CNF).......","Originating DC (CNF)...","Originating Time (CNF).","> > >DN (ORG)..........","objectClass (ORG)......","objectGUID (ORG).......","Originating DC (ORG)...","Originating Time (ORG)." } If ($numArgs -eq 1 -And ($arg0.ToLower() -eq "computer" -Or $arg0.ToLower() -eq "user")) { $adObj = "" | Select "> > >DN (CNF)..........","objectClass (CNF)......","objectGUID (CNF).......","Account Name (CNF).....","PWD Last Set (CNF).....","Originating DC (CNF)...","Originating Time (CNF).","> > >DN (ORG)..........","objectClass (ORG)......","objectGUID (ORG).......","Account Name (ORG).....","PWD Last Set (ORG).....","Originating DC (ORG)...","Originating Time (ORG)." } $adObj."> > >DN (CNF).........." = $dnCNFobj $adObj."objectClass (CNF)......" = $classCNFobj $adObj."objectGUID (CNF)......." = $guidCNFobj If ($numArgs -eq 1 -And ($arg0.ToLower() -eq "computer" -Or $arg0.ToLower() -eq "user")) { $adObj."Account Name (CNF)....." = $sAMAccountCNFobj $adObj."PWD Last Set (CNF)....." = $pwdLastSetCNFobj } $adObj."Originating DC (CNF)..." = $objCNFOrigSrv $adObj."Originating Time (CNF)." = $objCNFOrigTime $adObj."> > >DN (ORG).........." = $dnORGobj $adObj."objectClass (ORG)......" = $classORGobj $adObj."objectGUID (ORG)......." = $guidORGobj If ($numArgs -eq 1 -And ($arg0.ToLower() -eq "computer" -Or $arg0.ToLower() -eq "user")) { $adObj."Account Name (ORG)....." = $sAMAccountORGobj $adObj."PWD Last Set (ORG)....." = $pwdLastSetORGobj } $adObj."Originating DC (ORG)..." = $objORGOrigSrv $adObj."Originating Time (ORG)." = $objORGOrigTime $listOfDuplicates += $adObj } Write-Host "" If ($numArgs -eq 0) { Write-Host "LIST OF DUPLICATE/CONFLICTING OBJECTS IN THE AD FOREST" -Foregroundcolor Cyan } If ($numArgs -eq 1 -And $arg0.ToLower() -eq "computer") { Write-Host "LIST OF DUPLICATE/CONFLICTING COMPUTER OBJECTS IN THE AD FOREST" -Foregroundcolor Cyan } If ($numArgs -eq 1 -And $arg0.ToLower() -eq "user") { Write-Host "LIST OF DUPLICATE/CONFLICTING USER OBJECTS IN THE AD FOREST" -Foregroundcolor Cyan } $listOfDuplicates | FL } Else { Write-Host "NO DUPLICATE/CONFLICTING OBJECTS DETECTED IN THE AD FOREST" -Foregroundcolor Green }

The following is an example result when executing the script as: .\Retrieve-List-Of-Conflicting-Objects.ps1

image

Figure 1: Detecting Conflicting/Duplicate Objects In The AD Forest

The following is an example result when executing the script as: .\Retrieve-List-Of-Conflicting-Objects.ps1 computer

image

Figure 2: Detecting Conflicting/Duplicate Computer Objects In The AD Forest

The following is an example result when executing the script as: .\Retrieve-List-Of-Conflicting-Objects.ps1 user

image

Figure 3: Detecting Conflicting/Duplicate User Objects In The AD Forest

Get the PowerShell code from HERE.

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/ ########

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

4 Responses to “(2014-09-17) Finding Conflicting Objects In Your AD”

  1. Hello Jorge, and thanks for writing a great and very informative blog🙂

    I have a question about this particular blog post

    If left alone with AD internal garbage collection remove the duplicate using the tombstone life time settings?

    Thanks
    AAnotherUser__

    • Jorge said

      No, those objects will not be removed by AD itself. You will have to delete the “wrong” object yourself, but first you need to determine which of the objects is the “wrong” object. AD just does what it needs to do to make every object unique.
      AD will will only manage objects automatically, using pre-configured lifetimes, after YOU have deleted an object

  2. albertwt said

    Jorge,

    If I need to scheduled task this script monthly, what is the minimum permission account I need to use apart from the DOMAIN\Administrator account ?

    Thanks for the script.

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: