Lately it seems a number of people are trying to compare group membership between Active Directory groups. Often they are trying to use PowerShell (a good choice) so I thought I’d share some techniques you can use.

For this article I’m going to assume you are using the Microsoft Active Directory module from a member desktop running at least PowerShell 3.0. If you are using the Quest Active Directory cmdlets, you should be able to use the concepts but naturally change the cmdlet names.

For the sake of the demonstration I have two small global security groups, although it doesn’t really matter the scope or type.

PS C:\> $a= Get-ADGroupMember GroupA
PS C:\> $a | Select name

name
----
Ahmad Castelum
Amber Kasey
Alexis Hembrey
Andra Papallo
Anderson Lefurgy

PS C:\> $b = Get-ADGroupMember GroupB
PS C:\> $b| Select name

name
----
Catherina Olexy
Amber Kasey
Bettina Tamburri
Berry Tototzintle
Ashley Abramian
Andra Papallo
Anderson Lefurgy

I’m using the Name property, but you might want to use samAccountName as that should be unique. Visually, you can probably identify members in both groups or in only one group.

Remember, $a and $b are collections (or arrays) of Active Directory user objects. As such, I can compare the objects.

PS C:\> compare-object $a $b

InputObject                             SideIndicator
-----------                             -------------
CN=Catherina Olexy,OU=Demo,OU=Employ... =>
CN=Bettina Tamburri,OU=Demo,OU=Emplo... =>
CN=Berry Tototzintle,OU=Demo,OU=Empl... =>
CN=Ashley Abramian,OU=Demo,OU=Employ... =>
CN=Ahmad Castelum,OU=Demo,OU=Employe... <=
CN=Alexis Hembrey,OU=Demo,OU=Employe... <=

Here, $a is the reference object and $b is the difference object. The SideIndicator shows which object only belongs in a particular group. In this example, the displayed inputobject makes it pretty clear which user account belongs to which group. But you can fine tune the comparison by specifying a property name.

PS C:\> compare-object $a $b -Property name

name                                    SideIndicator
----                                    -------------
Catherina Olexy                         =>
Bettina Tamburri                        =>
Berry Tototzintle                       =>
Ashley Abramian                         =>
Ahmad Castelum                          <=
Alexis Hembrey                          <=

Much better.

But I expect you need more than that. You probably want to find users in Group A that are also in Group B.

PS C:\> $a.name | where {$b.name -contains $psitem}
Amber Kasey
Andra Papallo
Anderson Lefurgy

This expression uses a trick introduced in PowerShell 3 that allows you to enumerate a single property (e.g. Name) for an array of objects. The command says “Go through all the names from $a where the collection of names from $b contains a matching name.” I’m using $psitem but you can also use $_.

Or maybe you need to opposite: users in Group A that are NOT in Group B.

PS C:\> $a.name | where {$b.name -notcontains $psitem}
Ahmad Castelum
Alexis Hembrey

My groups only have a small number of users but it wouldn’t matter if there were 10 or 1000 users. And certainly you can flip this around.

PS C:\> $b.name | where {$a.name -notcontains $psitem}
Catherina Olexy
Bettina Tamburri
Berry Tototzintle
Ashley Abramian

These are the users in Group B that are NOT in Group A. What you do with this information is up to you. If you are working in a pipeline expression, it might be more useful to get the full user object. I’ve just been filtering on the name but there’s no reason I can’t filter on the full user object.

PS C:\> $a | where {$b.samaccountname -notcontains $psitem.samaccountname}

distinguishedName : CN=Ahmad
                    Castelum,OU=Demo,OU=Employees,DC=GLOBOMANTICS,DC=local
name              : Ahmad Castelum
objectClass       : user
objectGUID        : 5632694a-37c1-44e2-8666-2e1da10bd4f7
SamAccountName    : ACastelum
SID               : S-1-5-21-2552845031-2197025230-307725880-8629

distinguishedName : CN=Alexis
                    Hembrey,OU=Demo,OU=Employees,DC=GLOBOMANTICS,DC=local
name              : Alexis Hembrey
objectClass       : user
objectGUID        : ee5d1689-6e17-4cf5-880b-5889ea929301
SamAccountName    : AHembrey
SID               : S-1-5-21-2552845031-2197025230-307725880-8650

Here then are the user objects for members of Group A that are not in Group B. For example, perhaps you need to disable accounts that aren’t in Group B.

Subscribe to 4sysops newsletter!

PS C:\> $a | where {$b.samaccountname -notcontains $psitem.samaccountname} | Disable-ADAccount -whatif
What if: Performing the operation "Set" on target "CN=Ahmad Castelum,OU=Demo,OU=Employees,DC=GLOBOMANTICS,DC=local".
What if: Performing the operation "Set" on target "CN=Alexis Hembrey,OU=Demo,OU=Employees,DC=GLOBOMANTICS,DC=local".

Once you’ve learned the syntax of working with arrays of objects it doesn’t matter if they are AD users, files or processes. If you are still struggling to grasp some PowerShell fundamentals, I encourage you to pick up a copy of Learn Windows PowerShell 3 in a Month of Lunches or my video courses at Pluralsight.com.

+2
2 Comments
  1. Wighty05 5 years ago

    I'm using this method and trying to get the output formatted to "SamAccountName, employeeid, displayname, mail" to no success, any help would be great

    $Results1 = $a.samaccountname | where {$b.samaccountname -notcontains $psitem}

    $Results1 | Sort-Object DisplayName | ForEach-Object {Add-Member -InputObject $_ -Type NoteProperty -Name SamAccountName -Value $_; $_} | ConvertTo-Html -Head $head -Body $strMail1 -Property SamAccountName | Out-File $Report1

    and it emails the $Report1

    0

  2. Jay 5 years ago

    Thanks for your blog post.  Saved me a lot of time!  One question though.

    I'm trying to output the names of people in Group B that are not in Group A into a CSV file with:

    $b.name | where {$a.name -notcontains $psitem} | export-csv -Path c:\file.csv -NoTypeInformation

    but the output appears to just be the length of each name rather than the names themselves.

    0

Leave a reply

Please enclose code in pre tags

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2021

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account