Getting users group membership (tokengroups)
Around the same time as I wrote my Linked-Value Attribute script I also came up with this little gem. It also uses a constructed attribute provided with Windows 2003 called “tokengroups.” (Did I mention this includes recursive groups?)
Effectively it gets the attribute which returns an array of SIDs (in byte array form) for each group. I then use a function I posted about eariler called ConvertTo-Name to convert that BYTE array into a friendly group name we humans like.
Parameters:
- - Account: Can be User samAccountName or DN of the user
- - Verbose: Enables verbose output
More Info:
You may notice the GetInfoEx call I make on the user object. This is because tokengroups is not an actual attribute and does not get “populated” until you specifically request it. The GetInfoEx does exactly that.
Links:
MSDN: GetInfoEx
MSDN: tokenGroups
Get-TokenGroups.ps1
if($verbose){$verbosepreference="Continue"}
Write-Host
Write-Verbose " – Account: $Account"
Write-Verbose " – Verbose: $Verbose"
function ConvertTo-Name($sid,[switch]$FromByte) {
if($FromByte)
{
$ID = New-Object System.Security.Principal.SecurityIdentifier($sid,0)
}
else
{
$ID = New-Object System.Security.Principal.SecurityIdentifier($sid)
}
if($ID)
{
$User = $ID.Translate([System.Security.Principal.NTAccount])
$User.Value
}
}
function GetDNfromName{
Param($name)
$root = [ADSI]""
$filter = "(sAMAccountName=$name)"
$props = @("distinguishedName")
$Searcher = new-Object System.DirectoryServices.DirectorySearcher($root,$filter,$props)
$Searcher.FindOne().properties.distinguishedname
}
if($Account -notmatch "CN=(.*),((OU|DC)=\w*)*")
{
Write-Verbose " + Getting User DN for [$Account]"
$Account = GetDNfromName $Account
Write-Verbose " – GetDNfromName returned [$Account]"
}
Write-Verbose " – Getting User Object"
$UserAccount = [ADSI]"LDAP://$Account"
Write-Verbose " – Calling GetInfoEx"
$UserAccount.GetInfoEx(@("tokengroups"),0)
Write-Verbose " – Getting tokengroups"
$groups = $UserAccount.Get("tokengroups")
Write-Verbose " + Processing Groups"
foreach($group in $groups)
{
$GroupName = ConvertTo-Name $group -FromByte
Write-Verbose " – Found group [$GroupName]"
$GroupName
}
Write-Host


This is very useful. I’ve been trying to figure out an easy way to convert the byte array sid into a string. Instead of a switch on convertto-name, why not test the object type? Like if ($sid -isa [byte[]] { } else { } ? Just a thought, I’ll probably play around with it some.
Thanks!
- Robbie