best business builder

How To Find Nested Active Directory Group Memberships in PowerShell

Find the actual number of users in a group by locating those that may be hard to find in a hidden subgroup.

As someone that manages Active Directory users and groups, trying to figure out the true membership of a particular group can be hard. Why? It’s because of the way in which Active Directory allows groups to nested inside one another.

Let’s say that I have a group called Grandparent. This group is then assigned various permissions throughout your environment. One day you discover that a user that was assigned to a group called Child is somehow inheriting the rights that the Grandparent group has. How did this happen? This could easily happen if this Child group is nested inside of one or more other groups that have different ACLs set in the same places. There are lots of scenarios like this I’ve personally come across in my years of managing Active Directory and it’s a topic that can have major consequences if not addressed properly.

When you add a user into a group with Active Directory Users and Computers you don’t have an easy way to determine what groups this user will truly be a member of. You aren’t able to see parent groups of the group at hand. By using PowerShell though, we can use the power of recursion to allow you to specify a group and then be able to find all the users that group truly has.

To do this, we’ll first need to figure out any groups that are members of that group, query each of those groups and continue doing this until we come to a group that has no other nested groups. This is recursion and, with PowerShell, we can create a function that can automatically do this for us.

First, you’ll need to ensure you have the Remote Server Administration Tools installed and I’m assuming that you had read permissions in Active Directory to read group memberships. I’ll be performing this on domain-joined computer.

I have a group called Grandparent in Active Directory. I first need to determine its membership. I can do this through the Get-ADGroupMember cmdlet. I’ll first check out the members of the Grandparent group.

PS> Get-ADGroupMember Grandparent

You’ll see that I just have a single member and it’s a group called Parent. Now, let’s see what members the Parent group has.

PS> Get-ADGroupMember Parent

 

I just have another group called Child. I do the same for Child.

PS> Get-ADGroupMember Child

You can see that I finally come to the end of the line with only a single user object in the Child group. At this point, we don’t need to query any other group memberships to get a true picture of all users being “in” the Grandparent group.

We now need to do this automatically with a function rather than manually querying each group’s membership.

 

function Get-NestedGroupMember 
  {
  [CmdletBinding()] 
  param 
  (
  [Parameter(Mandatory)] 
  [string]$Group 
  )
  
  ## Find all members  in the group specified 
  $members = Get-ADGroupMember -Identity $Group 
  foreach ($member in $members)
  {
  ## If any member in  that group is another group just call this function again 
  if ($member.objectClass -eq 'group')
  {
  Get-NestedGroupMember -Group $member.Name
  }
  else ## otherwise, just  output the non-group object (probably a user account) 
  {
  $member.Name  
  }
  }
  }


You can see from above, I’ve built a small function called Get-NestedGroupMember. It’s a function that uses recursion to call itself when it encounters another group nested inside of a group. If it detects that a group member is not a group it will simply output the name of that object to the console.

I’ve run this function against the same scenario as I explained earlier with the Grandparent/Parent/Child groups.  Now, instead of having to manually run Get-ADGroupMember for each of these groups I can now simply pass the group name of Grandparent to my Get-NestedGroupMember function and immediately see my user account of Adam Bertram.

PS> Get-NestedGroupMember –Group Grandparent
customer relationships

Leave a Reply

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