Get direct and nested Active Directory group membership with PowerShell (2023)

2019-03-16 7 min read activedirectory powershell Geoff

This post lists various methods to get all the groups a Windows user is a member of (direct and through group nesting)

Active Directory supports multiple levels of group nesting. A user or computer can therefore be a direct member of a group, or an indirect member via a nested group. The Windows security token used to authorise a security principlal’s access to resources includes all group memberships - direct and nested.

The MemberOf attribute of an Active Directory user or computer object only contains the direct group memberships.

(Video) Get members of multiple Security Groups using PowerShell

Listing all groups (direct and nested) is neccessary when troubleshooting access to resources.

Built-in Method- WHOAMI

Whoami.exe is built-in to Windows. The /groups option shows the direct and nested groups of the current user. It is limited as it can only be used for the current user. Specify CSV output and PowerShell can convert it into a PSObject

whoami /groups /fo csv | convertfrom-csv | out-gridview

Active Directory PowerShell Module

The Microsoft AD PowerShell module (available with the RSAT tools) does not contain a command to get all groups for a given user.
It does contain a command to recursively look-up the members of a group to get the direct and indirect members:

Get-ADGroupMember -Identity MyGroup -Recursive
(Video) 12. Get members of all Active Directory Groups with PowerShell

.NET GetAuthorizationGroups()

The ‘System.DirectoryServices.AccountManagement’ class is a .NET framework (Full version) class. It contains a method called GetAuthorizationGroups that returns direct and indirect groups for a user account.

The GetAuthorizationGroup function below is convenient as it works with a username rather than requiring a distinguishedName

PowerShell Script

GetAuthorizationGroups can be used for the current user account or an alternate user. The following PowerShell function demonstrates the method:

Function Get-AuthorizationGroup { <# .SYNOPSIS Returns all the groups (including nested) that an Active Directory domain user is a member of .DESCRIPTION Uses the .NET class method: System.DirectoryServices.AccountManagement.UserPrincipal.GetAuthorizationGroups() Returns the name, Description and distinguishedname of each group the user is a member of. The domain must be available or the function will return an error. .PARAMETER Userid The samAccountName of a domain user .EXAMPLE Get-AuthorizationGroup -userid jsmith This command will list the name,description and distinguishedName of groups that the domain user with userid jsmith is a member of .NOTES Author: @Writeverbose Version: 1.0 #> [cmdletbinding()] param( $Userid ) PROCESS { Add-Type -AssemblyName System.DirectoryServices.AccountManagement try { $principalCtx = new-object System.DirectoryServices.AccountManagement.PrincipalContext('Domain') $QueryUser = new-object System.DirectoryServices.AccountManagement.UserPrincipal ($principalCtx) $QueryUser.SamAccountName = $Userid $principalSearcher = new-object System.DirectoryServices.AccountManagement.PrincipalSearcher $principalSearcher.QueryFilter = $QueryUser $userPrincipal = $principalSearcher.FindOne() } catch { Write-error "Failed to access domain : check connectivity ($_)" } if (-not($null -eq $userPrincipal)) { $groups = $userPrincipal.GetAuthorizationGroups() $groups | Select samAccountName, Description, distinguishedname } else { Write-Error "User was not found in the domain" } }}

AD TokenGroups - method 1

TokenGroups is a constructed attribute of Active Directory user and computer objects that contains all their group memberships.

(Video) An investigation into nested group membership in Active Directory

Constructed attributes are only generated when queried. In this case, TokenGroups effectively explodes the security token so that the list contains the SIDs of direct and indirect groups.

In the PowerShell function below, a .NET method is then used to convert the SIDs to group names: System.Security.Principal.SecurityIdentifier::Translate()

The function requires the distinguishedName of an Active Directory user or computer as input.

PowerShell Script

Function Get-TokenGroup1 { <# .SYNOPSIS Returns all the groups (including nested) that an Active Directory domain user is a member of .DESCRIPTION Uses the TokenGroups calculated attribute to get group membershipsA connection to a domain controller is required - TokenGroups returns a list of ObjectSIDs - The ObjectSID of each group is resolved to a name using System.Security.Principal.SecurityIdentifier.Translate() .PARAMETER distinguishedName The DN of an Active Directory user or computer account e.g. CN=jsmith,OU=Europe,OU=Accounts,DC=mydomain,DC=com .PARAMETER Server The name of an Active Directory Domain Controller or AD Domain The default is the %USERDNSDOMAIN% environment variable .EXAMPLE Get-TokenGroup1 -distinguishedName "CN=jsmith,OU=Europe,OU=Accounts,DC=mydomain,DC=com" This example will get the direct and indirect (nested) group memberships of the jsmith user accvount in the mydomain Active Directory domain. .NOTES Author: @WriteVerbose Version: 1.0 #> [cmdletBinding()] param( [parameter(mandatory = $true, position = 0, valuefrompipeline = $True, valuefrompipelinebypropertyName = $True)] [ValidatePattern("CN=(.*),((OU|DC)=\w*)*")] [string]$DistinguishedName , [string]$Server = $ENV:USERDNSDOMAIN ) PROCESS { try { $ADObj = [ADSI]"LDAP://$Server/$DistinguishedName" # Calculated property so need to refreshCache... $ADObj.psbase.RefreshCache("tokenGroups") $SIDs = $ADObj.psbase.Properties.item("tokenGroups") } catch { Write-Error "Failed to find user on server '$Server' ($_)" } if (-not($null -eq $SIDs)) { ForEach ($Entry In $SIDs) { $SID = New-Object System.Security.Principal.SecurityIdentifier $Entry, 0 try { $Group = $SID.Translate([System.Security.Principal.NTAccount]) } catch { Write-warning "Failed to translate SID '$($SID.Value)' to a name" $Group = $null } [PSCustomObject][ordered]@{ UserDN = $ADObj.Properties.item("DistinguishedName")[0] UserDisplayName = $ADObj.Properties.item("DisplayName")[0] GroupSID = $SID.Value GroupDomain = $Group.Value.Split('\')[0] GroupName = $Group.Value.Split('\')[1] } } } else { Write-Warning "Didn't find any group memberships for user '$DistinguishedName'" } }}

TokenGroups - Method 2

The script below also uses the TokenGroups attribute to obtain the directed and nested group membership. The only difference from Method1 is the way the group SIDs are resolved to names.

(Video) How To Get Members Of Active Directory Group With Powershell In Windows Server 2012

In the example below, each SIDs is converted to an Octet string format that can be looked-up in AD using an LDAP query. The entire list of group Octet Strings is concatenated into a single LDAP query that returns the group names.

There is no real benefit to using Method2 over Method1. Method2 was the first way I solved this problem, before becoming aware of the previous .Net options that are more concise.

PowerShell Script

Function Get-TokenGroup2 { [cmdletBinding()] <#.SYNOPSISUsed to get the direct and nested group membership of an AD security principal (user or computer).DESCRIPTIONUses the TokenGroups calculated attribute to get group membershipsA connection to a domain controller is required- TokenGroups returns a list of ObjectSIDs- Script then performs an AD Query filtered using the SIDs to get the displayNamesReturns a string array of group names (without domain portion).PARAMETER DistinguishedNameThe distinguishedName of an Active Directory user or computere.g. "CN=jsmith,OU=Europe,OU=Accounts,DC=mydomain,DC=com".EXAMPLE PS C:\> Get-TokenGroup2 "CN=jsmith,OU=Europe,OU=Accounts,DC=mydomain,DC=com" This command will get the direct and indirect (nested) group membersjips of the jsmith user account in the mydomain Active Directory domain .NOTES Author: @WriteVerboseVersion: 1.0.Linkhttp://msdn.microsoft.com/en-us/library/windows/desktop/ms680275(v=vs.85).aspx#> param( [parameter(mandatory = $true, position = 0, valuefrompipeline = $True, valuefrompipelinebypropertyName = $True)] [ValidatePattern("CN=(.*),((OU|DC)=\w*)*")] [string]$DistinguishedName ) BEGIN { #REGION --- Support Functions --- Function Convert-ToLDAPFilter($Octet) { # This function is used to build an LDAP search string to convert Group SIDs from TokenGroups to samAccountNames [System.Text.StringBuilder]$sb = New-Object System.Text.StringBuilder("") # output object # Input is either a Byte or a Byte array if ($Octet.GetType().BaseType.Name -eq "Byte") { # Single entry $HexString = "\$(([System.BitConverter]::ToString($Octet)).Replace('-','\'))" $sb.Append("(objectSid=$HexString)") | Out-Null } elseif ($Octet.GetType().BaseType.Name -eq "Array") { # multiple entries # convert octet byte array to hex string and build ldap filter $sb.Append("(|") | Out-Null foreach ($group in $Octet) { $HexString = "\$(([System.BitConverter]::ToString($group)).Replace('-','\'))" $sb.Append("(objectSid=$HexString)") | Out-Null } $sb.Append(")") | Out-Null } else { # no entries } $sb.ToString() #return } # This function is used to execute the LDAP search string, to convert Group SIDs to samAccountNames Function Find-DirectoryEntry { <#.Synopsis Finds an Active Directory object using a directory search.Description Helper function to search AD using an LDAP query.Parameter FilterThe filter portion of the LDAP query.Parameter RootThe root container for the query.Parameter PropertyAn array of parameters to be returned.Parameter ScopeThe depth of the query - base,onelevel or subtree .Example PS C:\>Find-DirectoryEntry -Filter "(objectClass=computer)" -Property "*"This command will return all computer objects in the domain of the current user and include all available properties .Example PS C:\>Find-DirectoryEntry -Filter "(objectClass=user)" -Property "displayName,givenName,sn" -root "cn=user,dc=my,dc=home"This command will return all user objects in the Users container of the my.home domain and include the displayName, givenName and surname properties .NotesVersion: 1.0Author: @WriteVerbose#> param( [parameter(position = 0, mandatory = $false)] [string]$Filter = "*" , [parameter(position = 1, mandatory = $false)] [string]$Root = $env:USERDNSDOMAIN , [parameter(position = 2, mandatory = $false)] [string[]]$Property = "*" , [parameter(position = 3, mandatory = $false)] [string]$Scope = "subtree" ) try { $DE = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$Root") $Searcher = New-Object System.DirectoryServices.DirectorySearcher $Searcher.SearchRoot = $DE $Searcher.PageSize = 1000 $Searcher.Filter = $Filter $Searcher.SearchScope = $Scope foreach ($entry in $Property) { $Searcher.PropertiesToLoad.Add($entry) } $Results = $Searcher.FindAll() # Return the DirectorySearcher.SearchResult object return $Results } catch [Exception] { Write-Error "Failed to find directory entry: $($_.Exception.MessageDetails)" Return $null } } #ENDREGION } PROCESS { # Requires a connection to a DC to complete try { $ADObj = [ADSI]"LDAP://$DistinguishedName" $ADObj.GetInfoEx(@("tokengroups"), 0) $groups = $ADObj.Get("tokengroups") # this returns an array of group SIDs } catch { Write-Error "Failed to find user on default domain ($_)" } if (-not($null -eq $groups)) { $Filter = Convert-ToLDAPFilter -Octet $groups # Build an LDAP query to convert the group SIDs to names # Execute the query against AD. Returns a SearchResult collection $Result = Find-DirectoryEntry -Filter $filter -Property "SamAccountName" # Convert the SearchResult collection to a string array of Group Names [String[]]$GroupNames = $($Result | Foreach { if ($_ -as [System.DirectoryServices.SearchResult]) { $_.Properties.Item("samAccountName")[0] } }) $GroupNames # output } else { Write-Warning "Didn't find any group memberships for user '$DistinguishedName'" } }#process}

This article was originally posted on Write-Verbose.com

FAQs

Where is nested Active Directory group membership in PowerShell? ›

We can get group members by using the Active Directory PowerShell cmdlet Get-ADGroupMember. The Get-ADGroupMember cmdlet provides the option to get all the nested group members by passing the parameter -Recursive.

How do I get AD user Group membership in PowerShell? ›

Use Get-ADGroupMember cmdlet to List Members of an Active Directory Group. The PowerShell Get-ADGroupMember cmdlet is used to list the members of an Active Directory group. You can just type the cmdlet in a PowerShell window and you'll be prompted to enter the name of the group you want to use.

What is nested group membership Active Directory? ›

Group nesting in Active Directory simplifies network management for administrators. It enables them to assign access rights and permissions to resources within the domain and across domains with ease.

How do I query a group membership in Active Directory? ›

You can check group membership with the Active Directory Users and Computers (ADUC) console snap-in by finding the user or group of interest and drilling down into the object's properties and clicking the “Members” or “Member Of” tab.

Videos

1. PowerShell-free AD reporting, Efficient AD accounts, group membership and NTF permissions management
(ManageEngine ADSolutions)
2. PowerShell-free AD reporting, Efficient AD accounts, group membership and NTFS permissions
(ManageEngine)
3. Script-free Active Directory reporting and efficient access management via group membership
(ManageEngine ADSolutions)
4. Retrieve All AD Nested groups and users under a group - C#
(Tech69)
5. Creating Dynamic nested Active Directory groups
(Imanami Corporation)
6. Active Directory Group Membership Reporter
(Paramount Defenses)
Top Articles
Latest Posts
Article information

Author: Carmelo Roob

Last Updated: 03/17/2023

Views: 6722

Rating: 4.4 / 5 (65 voted)

Reviews: 80% of readers found this page helpful

Author information

Name: Carmelo Roob

Birthday: 1995-01-09

Address: Apt. 915 481 Sipes Cliff, New Gonzalobury, CO 80176

Phone: +6773780339780

Job: Sales Executive

Hobby: Gaming, Jogging, Rugby, Video gaming, Handball, Ice skating, Web surfing

Introduction: My name is Carmelo Roob, I am a modern, handsome, delightful, comfortable, attractive, vast, good person who loves writing and wants to share my knowledge and understanding with you.