(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:
- "CN=TestObjectACNF:4862d44c-76ab-41b7-bac8-8682900e661b,OU=MyOU,DC=DOMAIN,DC=COM"
- "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
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
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
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/ ########
———————————————————————————————
aanotheruser said
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__
LikeLike
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
LikeLike
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.
LikeLike
Jorge said
this script just queries AD, therefore a regular user account should be good enough
LikeLike
vamdev mishra said
Hello Jorge, as you are also pulling replication metadata in the script so regular account would give you “Access Denied” Message, a privilege account would be required in that case.
LikeLike
Jorge said
Most likely I created and tested the script in my test environment with a high privileged account. Thinking about it, I think you are most likely right
LikeLike
Ranjith Kumar Neelagiri said
Hi Jorge,
Thanks for this excellent script.
needs a small modification on this script, we are thinking to automate and auto schedule this script on our AD database, Could you please share me your input for how to configure email notify when generates CNF account or generate the report in HTML format…?
LikeLike
Ranjith Kumar Neelagiri said
Hi Jorge,
While running this code in my environment, i am getting the following error message, could you please check and acknowledge on my query.
Get-ADObject : This operation returned because the timeout period expired
At line:17 char:33
+ $listOfConflictingObjects = Get-ADObject -server $gcHostPort -LDAPFilter ‘(n …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-ADObject], ADException
+ FullyQualifiedErrorId : ActiveDirectoryServer:1460,Microsoft.ActiveDirectory.Management.Commands.GetADObject
NO DUPLICATE/CONFLICTING OBJECTS DETECTED IN THE AD FOREST
LikeLike