List all of a users group memberships
Download the script here
Auditing user access is hard, usually you audit from resource out - eg, finding all Domain Admins, or finding all users with full acecss to SecretShare$ share on SecretServer01. But occasionally want to audit from user out.. this is hard.. even impossible (if you have a very big environment). Lets talk about the first step Enumerating Nested Groups.
Token Groups
Each user has a constructed attribute called tokengroups
that returns a list of all transitive group memberships. You can query tokengroups
using get-adobject
like this…
$userDN = 'CN=Tom,OU=sales,DC=wrish,DC=com'
get-adobject -SearchBase $userDN -SearchScope Base -Properties TokenGroups -filter *
… but there are a couple of problems, you get back SIDs and only SIDs, that means no Distribution Only groups and you have to manually convert them into objects or DNs if you want useful visual reporting. You can do that pretty easily (but slowly) like this…
function get-TokenGroups ($objectDN) {
$ADObject = get-adobject -SearchBase $objectDN -SearchScope Base -Properties TokenGroups -filter *
foreach ($Sid in $ADObject.tokengroups){
([ADSI]"LDAP://<SID=$SID>").distinguishedname
}
}
get-TokenGroups 'CN=Tom,OU=sales,DC=wrish,DC=com'
… also, some groups are missing in a multi-domain environment - Domain Local groups in remote domains. Domain Local group memberships aren’t replicated to the Global Catalog, so the GC doesn’t add them to the tokengroups value when queried.
MemberOf Evaluation
Each user has a MemberOf
attribute which you can query recursively to get at all those juicy remote domain groups. There are plenty of examples of these scripts available they usually commit the various sins of PowerShelling like exporting to csv or not generating objects at all or a particularly good one that even outputs some nice verbose info… but breaks when group memberships traverse domains.
They are also all incredibly complicated, sigh.
function EnumerateMemberOf($Object, $ResultSoFar=@())
{
#Helper function to walk $object's memberof attribute and list out all group memberships
if ($object.memberof){
$Results = @();
foreach ($group in $Object.memberof){
#prevent nesting loops trapping by checking to make sure the group hasn't been searched already
if ($ResultSoFar -notcontains $Group) {
#Bind directly to the group with ADSI - this will automatically follow referrals and work with
#multi domain forests
$TempGroup = [ADSI]"LDAP://$Group" ;
$ResultSoFar += $Group.ToString();
#Enumerate the next level of memberof
$Results += EnumerateMemberOf $TempGroup $ResultSoFar ;
$Results += $Group;
}
}
return $Results
}
}
function get-ADNestedMembership ($Identity)
$ADuser = get-aduser $Identity -Properties memberof,distinguishedname,primaryGroup
write-output (new-object psobject -property @{distinguishedname=$aduser.distinguishedname;'NestedMemberOf'=(@(enumerateMemberof $ADuser)+(enumerateMemberof (get-adgroup $AdUser.primaryGroup -properties memberof)))})
}
For the advanced functions (with pipline goodness) you’ll need to download it https://gallery.technet.microsoft.com/Get-nested-group-e9ce3687.