If you ever need to flatten out groups which may include nested local and AD groups there’s a really easy way to do this in the System.DirectoryServices.AccountManagement.GroupPrincipal GetMembers method. Here’s some PowerShell code which works against both local and AD groups. The code can easily be adapted into a function and in fact I’m using similar code in the SQLPSX project for SQL Server permission auditing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | add-type -AssemblyName System.DirectoryServices.AccountManagement $domain = "$env:computername" $groupname = "Administrators" #Determine if domain a machine or domain try { $domainName = [System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain() | select -ExpandProperty Name $isDomain = $domainName -match "$domain\." } catch { $isDomain = $false } if ($isDomain) { $ctype = [System.DirectoryServices.AccountManagement.ContextType]::Domain } else { $ctype = [System.DirectoryServices.AccountManagement.ContextType]::Machine } #Create objects to filter based on group name and ContextType--Domain or Machine $principal = new-object System.DirectoryServices.AccountManagement.PrincipalContext $ctype,$domain $groupPrincipal = new-object System.DirectoryServices.AccountManagement.GroupPrincipal $principal,$groupname $searcher = new-object System.DirectoryServices.AccountManagement.PrincipalSearcher $searcher.QueryFilter = $groupPrincipal #Note GetMembers($true) recursively enumerates groups members while GetMembers() simply enumerates group members $searcher.FindAll() | foreach {$_.GetMembers($true)} |