Use PowerShell to Determine the Differences in Group Membership between Active Directory Users
I recently saw a post on Reddit where someone was trying to create a function that takes an Active Directory user name as input for a manager who has direct reports (subordinates) specified in Active Directory. They wanted to determine if the Active Directory group membership of any of those subordinates is different than the others.
There are two different parts to this scenario. Returning a list of the manager's direct reports by querying that property from the manager's user account in Active Directory:
1Get-ADUser -Identity sbuchanan -Properties directReports |
2Select-Object -ExpandProperty directReports
I decided to keep that portion separate since it would be easy enough to accomplish that part of the task and hard coding that functionality would limit the re-usability of the group comparison portion of the tool. I wanted the users id's (input for my tool) to be able to come from a query against Active Directory, a list of user id's stored in a text file, or a CSV file (maybe an auditor supplies a list of user id's to compare that he emails to you).
The following PowerShell function compares the Active Directory user groups of one or more users. The function gets a combined list of all groups that the specified users are in. It then determines what are considered to be common groups between the users by determining which of those groups have 50% or more of the specified users in them. Finally, it iterates through each user comparing their group membership to the common group list and returns the user's group membership where it differentiates from the list.
1#Requires -Version 3.0
2#Requires -Modules ActiveDirectory
3function Compare-MrADGroup {
4
5<#
6.SYNOPSIS
7 Compares the groups of a the specified Active Directory users.
8
9.DESCRIPTION
10 Compare-MrADGroup is a function that retrieves a list of all the Active
11 Directory groups that the specified Active Directory users are a member
12 of. It determines what groups are common between the users based on
13 membership of 50% or more of the specified users. It then compares the
14 specified users group membership to the list of common groups and returns
15 a list of users whose group membership differentiates from that list. A
16 minus (-) in the status column means the user is not a member of a common
17 group and a plus (+) means the user is a member of an additional group.
18
19.PARAMETER UserName
20 The Active Directory user(s) account object to compare. Can be specified
21 in the form or SamAccountName, Distinguished Name, or GUID. This parameter
22 is mandatory.
23
24.PARAMETER IncludeEqual
25 Switch parameter to include common groups that the specified user is a
26 member of. An equals (=) sign means the user is a member of a common group.
27
28.EXAMPLE
29 Compare-MrADGroup -UserName 'jleverling', 'lcallahan', 'mpeacock'
30
31.EXAMPLE
32 'jleverling', 'lcallahan', 'mpeacock' | Compare-MrADGroup -IncludeEqual
33
34.EXAMPLE
35 Get-ADUser -Filter {Department -eq 'Sales' -and Enabled -eq 'True'} |
36 Compare-MrADGroup
37
38.INPUTS
39 String
40
41.OUTPUTS
42 PSCustomObject
43
44.NOTES
45 Author: Mike F Robbins
46 Website: http://mikefrobbins.com
47 Twitter: @mikefrobbins
48#>
49
50 [CmdletBinding()]
51 param (
52 [Parameter(Mandatory,
53 ValueFromPipeline)]
54 [string[]]$UserName,
55
56 [switch]$IncludeEqual
57 )
58
59 BEGIN {
60 $Params = @{}
61
62 If ($PSBoundParameters['IncludeEqual']) {
63 $Params.IncludeEqual = $true
64 }
65 }
66
67 PROCESS {
68 foreach ($name in $UserName) {
69 try {
70 Write-Verbose -Message "Attempting to query Active Directory of user: '$name'."
71 [array]$users += Get-ADUser -Identity $name -Properties MemberOf -ErrorAction Stop
72 }
73 catch {
74 Write-Warning -Message "An error occured. Error Details: $_.Exception.Message"
75 }
76 }
77 }
78
79 END {
80 Write-Verbose -Message "The `$users variable currently contains $($users.Count) items."
81
82 $commongroups = ($groups = $users |
83 Select-Object -ExpandProperty MemberOf |
84 Group-Object) |
85 Where-Object Count -ge ($users.Count / 2) |
86 Select-Object -ExpandProperty Name
87
88 Write-Verbose -Message "There are $($commongroups.Count) groups with 50% or more of the specified users in them."
89
90 foreach ($user in $users) {
91 Write-Verbose -Message "Checking user: '$($user.SamAccountName)' for group differences."
92
93 $differences = Compare-Object -ReferenceObject $commongroups -DifferenceObject $user.MemberOf @Params
94
95 foreach ($difference in $differences) {
96 [PSCustomObject]@{
97 UserName = $user.SamAccountName
98 GroupName = $difference.InputObject -replace '^CN=|,.*$'
99 Status = switch ($difference.SideIndicator){'<='{'-';break}'=>'{'+';break}'=='{'=';break}}
100 'RatioOfUsersInGroup(%)' = ($groups | Where-Object name -eq $difference.InputObject).Count / $users.Count * 100 -as [int]
101 }
102 }
103 }
104 }
105}
Now to use PowerShell to query the "Direct reports" of a manager in Active Directory and return those users as input for our group comparison tool:
That task can be performed with this simple PowerShell one-liner:
1Get-ADUser -Identity sbuchanan -Properties directReports |
2Select-Object -ExpandProperty directReports |
3Compare-MrADGroup
As shown in the previous set of results, a minus in the status column means the user is not a member
of a common group and a plus means they are a member of an extra group other than the common ones.
The RatioOfUsersInGroup(%)
column returns a percentage value of how many users are in the
specified group, for example 50% (3 of the 6 users) are in both the Faculty and Staff groups and
only 17% (1 of the users) is in the Test01 group.
1Compare-MrADGroup -UserName 'jleverling', 'lcallahan', 'mpeacock' -IncludeEqual
An equal sign will only show up in the status column when the IncludeEqual
parameter is
specified. It means that the users are included in the common group(s) as shown in the previous
example.
Update:
The most recent version of the Compare-MrADGroup
function shown in this blog article can be
downloaded from
my ActiveDirectory repository on GitHub.
µ