9

I'm trying to get ALL the groups a user is member, even the nested ones (recusively), in Powershell I'm using:

(Get-ADUser <username> -Properties MemberOf | Select-Object MemberOf).MemberOf

But it only returns the groups the user is a "direct" member, like you get when using the AD users console. I single list of ALL the groups is very helpful, like the output from "gpresult -r", where it shows ALL the groups the user is a member.

Is there a way to get it from any AD user? (Doesnt need to be exclusively in Powershell, maybe theres another tool that I dont know yet)

ekad
  • 14,436
  • 26
  • 44
  • 46
esserafael
  • 195
  • 1
  • 1
  • 6

3 Answers3

28

You can use the LDAP_MATCHING_RULE_IN_CHAIN:

Get-ADGroup -LDAPFilter "(member:1.2.840.113556.1.4.1941:=CN=User,CN=USers,DC=x)"

You can use it anywahere that you can use an LDAP filter.

Example:

$username = 'myUsername'
$dn = (Get-ADUser $username).DistinguishedName
Get-ADGroup -LDAPFilter ("(member:1.2.840.113556.1.4.1941:={0})" -f $dn) | select -expand Name | sort Name
JohnLBevan
  • 22,735
  • 13
  • 96
  • 178
Joseph Alcorn
  • 2,322
  • 17
  • 23
  • 1
    I am stunned at just how great that is, and if I could +1 this more than once I would. I just read the related documentation in the link you provided and that is truly valuable knowledge to anybody dealing with powershell, AD, and groups/members. – TheMadTechnician May 08 '14 at 22:53
  • NB: this appears to be limited to a single-domain search base. i.e. if the user is a member of a group in a different domain, or one of the groups is itself a member of a group in another domain, those on the other domain won't show up / will be excluded from the tree (i.e. even if the groups on the other domain are members of groups on the original domain). – JohnLBevan Mar 26 '15 at 17:19
  • @Joseph Alcorn , any idea why it doesn't show me the "Domain Users" group ? When I use `Get-ADPrincipalGroupMembership myUser` it shows me the user's groups (between them also "Domain Users"). When I search with: `$dn = (Get-ADUser "myUser").DistinguishedName Get-ADGroup -LDAPFilter ("(member:1.2.840.113556.1.4.1941:={0})" -f $dn) | select -expand Name | sort Name` it ignores the "Domain Users" group but show me all the rest of the groups (also recursive) – E235 Oct 01 '17 at 14:34
  • 2
    @E235, When a user has a certain group as the primary group, that link is not stored in the group's `member` attribute. Instead, the relative ID (RID) is stored on the user object in the `primaryGroupID` attribute. By default in AD, the primary group is always set to 'Domain Users'. If you look at that group's member attribute, you will see that it is empty. – Joseph Alcorn Oct 10 '17 at 06:00
  • 1
    This is not useful as it times out. – zendu Oct 18 '18 at 23:43
5

Or, you can use the constructed attribute tokenGroups and a base-scoped query:

$tokenGroups = Get-ADUser -SearchScope Base -SearchBase '<account-distinguishedName>' `
-LDAPFilter '(objectClass=user)' -Properties tokenGroups | Select-Object `
-ExpandProperty tokenGroups | Select-Object -ExpandProperty Value
user2871239
  • 1,499
  • 2
  • 11
  • 27
0

Expanding on user2871239 answer about using tokenGroups:

To get all AD object groups recursively:

((Get-ADUser username | Get-ADUser -Properties tokenGroups).tokenGroups | Get-ADGroup).Name

Or, if you don't need an ADGroup object, this returns a String instead, but is way faster:

(Get-ADUser username | Get-ADUser -Properties tokenGroups).tokenGroups.Translate([System.Security.Principal.NTAccount]).Value

It's almost instantaneous in our directory:

PS C:\windows\System32> (Get-ADUser -Filter *).Count
86816
PS C:\windows\System32> (Get-ADGroup -filter *).Count
1808
PS C:\windows\System32> (Get-ADComputer -filter *).Count
2666

Just for reference, here how much time it takes in this instance:

# this returns String objects
1..10 | % {
    Measure-Command {
        (Get-ADUser marcos | Get-ADUser -Properties tokenGroups).tokenGroups.Translate([System.Security.Principal.NTAccount]).Value
    }
} | Measure-Object -Average TotalSeconds | select @{l="Type";e={"String"}},Average

# this returns ADGroup objects
1..10 | % {
    Measure-Command {
        ((Get-ADUser marcossantos | Get-ADUser -Properties tokenGroups).tokenGroups | Get-ADGroup).Name
    }
} | Measure-Object -Average TotalSeconds | select @{l="Type";e={"ADGroup"}},Average

Type       Average
----       -------
String  0.01415692
ADGroup 0.25427236

This also returns nested membership of primaryGroup (usually Domain users), which most solutions does not account for.

One downside of this approach is that it does not retrieve distribution groups. If you need that, following query returns just distribution groups, using LDAP_MATCHING_RULE_IN_CHAIN (way faster than retrieving all groups, though):

Get-ADGroup -LDAPFilter "(&(groupType>=0)(member:1.2.840.113556.1.4.1941:=CN=myuser,OU=MyUsers,DC=example,DC=com))"

tokenGroups
LDAP_MATCHING_RULE_IN_CHAIN
Microsoft page about tokenGroups

Marcos Oliveira
  • 449
  • 4
  • 4