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