What’s the member delta between my two AD Groups

 

Today I am going to refresh your memory on how we can use the Compare-Object cmdlet to do well exactly what it says …. compare two different objects.

So how do I determine which Active Directory group members are in one group and not in another? And… I want those missing (delta-ed) members put into an entirely new one.

Sure, there are many ways to do this including nested loops but the Compare-Object cmdlet makes it easy. The Compare-Object cmdlet compares two sets of objects. One set of objects is the Reference set, and the other set is the Difference set.

The result of the comparison indicates whether a property value appeared only in the object from the Reference set (indicated by the <= symbol), only in the object from the Difference set (indicated by the => symbol) or, if the IncludeEqual parameter is specified, in both objects (indicated by the == symbol).

Code Snippet

param
(
    $ReferenceGroupDN = "cn=ReferenceGroup,ou=MyTestOU,dc=contoso,dc=com",
    $DifferenceGroupDN = "cn=DifferenceGroup,ou=MyTestOU,dc=contoso,dc=com",
    $TargetGroupDN = "cn=TargetGroup,ou=MyTestOU,dc=contoso,dc=com"
)

# Import the AD module
Import-Module -Name ActiveDirectory

# Declare Variables
$ReferenceUsers = Get-ADGroupMember -Identity $ReferenceGroupDN
$DifferenceUsers = Get-ADGroupMember -Identity $DifferenceGroupDN

# See what distinguished names are present in DifferenceUsers but not in ReferenceUsers
$userDifferenceArray = Compare-Object -ReferenceObject $ReferenceUsers `
    -DifferenceObject $DifferenceUsers -Property DistinguishedName -IncludeEqual -PassThru | `
        Where-Object { $_.SideIndicator -eq "=>" }
   
# Add to the Target Group - $TargetGroupDN
Add-ADGroupMember -Identity $TargetGroupDN -Members $userDifferenceArray

Explanation

In my test case, ReferenceGroup has the users Test2, Test4, and Test5. DifferenceGroup has the users Test1, Test2, Test3. All are within the MyTestOU OU of my virtual contoso.com domain.

ReferenceGroup Members
ReferenceGroup
DifferenceGroup Members
DifferenceGroup

We are here to show Compare-Object so lets use it to compare the two AD objects based on the DistinguishedName attribute. All we need to do is run these lines:

This block just gives us the top-level members:


# Declare Variables
$ReferenceUsers = Get-ADGroupMember -Identity $ReferenceGroupDN
$DifferenceUsers = Get-ADGroupMember -Identity $DifferenceGroupDN

# See what distinguished names are present in DifferenceUsers but not in ReferenceUsers
Compare-Object -ReferenceObject $ReferenceUsers `
-DifferenceObject $DifferenceUsers -Property DistinguishedName -IncludeEqual


Executing the above line will give us this output:

compare-object

We read it by using the SideIndicator property. As the documentation states, the “==” means the DistinguishedName was present in both the ReferenceObject and DifferenceObject. The “=>” means it was present only in the DifferenceObject. The “<=” means the property was only present in the ReferenceObject.

So if all I care about are those in the DifferenceObject that are not present in the ReferenceObject then we filter on the “=>” using a Where-Object.


# See what distinguished names are present in DifferenceUsers but not in ReferenceUsers
$userDifferenceArray = Compare-Object -ReferenceObject $ReferenceUsers `
-DifferenceObject $DifferenceUsers -Property DistinguishedName -IncludeEqual -PassThru | `
Where-Object { $_.SideIndicator -eq "=>" }

# Add to the Target Group - $TargetGroupDN
Add-ADGroupMember -Identity $TargetGroupDN -Members $userDifferenceArray


You might have noticed that I also used the parameter “PassThru”. It allows me to keep the original type name which was Microsoft.ActiveDirectory.Management.ADPrincipal. If I don’t use the parameter "PassThru" the typename is System.Management.Automation.PSCustomObject.

Add-ADGroupMember’s parameter “Members” supports the ADPrincipal type so all is good. It does not support a PSCustomObject type.

The end result:

TargetGroup