1

On an Active Directory domain member running Windows 7 I have a local group. It has users and other groups as members:

enter image description here

How can I obtain the SID for each member of this local group? I'm aware of the Sysinternals utility PSGetSid but it doesn't seem to be able to enumerate group members.

I say Reinstate Monica
  • 3,132
  • 7
  • 28
  • 52

2 Answers2

4

Here's a Powershell function you should be able to use. I only tested it on Windows 10, but I don't think it's using anything that wasn't available in Windows 7.

Function Get-LocalGroupMembers  {

[Cmdletbinding()] 
Param( 
    [Parameter(Mandatory=$true)]
    [string]$GroupName
)

[adsi]$adsiGroup = "WinNT://$($env:COMPUTERNAME)/$GroupName,group"

$adsiGroup.Invoke('Members') | %{

    $username = $_.GetType().InvokeMember('Name','GetProperty',$null,$_,$null)
    $path = $_.GetType().InvokeMember('AdsPath','GetProperty',$null,$_,$null).Replace('WinNT://','')
    $class = $_.GetType().InvokeMember('Class','GetProperty',$null,$_,$null)
    $userObj = New-Object System.Security.Principal.NTAccount($username)
    $sid = $userObj.Translate([System.Security.Principal.SecurityIdentifier])

    [pscustomobject]@{
        Username = $username
        Type = $class
        SID = $sid
        Path = $path
    }

}

}
Ryan Bolger
  • 16,755
  • 4
  • 42
  • 64
  • +1 You'll be happy to upgrade to WMF 5.1, it includes a [`Get-LocalGroupMember`](https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.localaccounts/get-localgroupmember) among other cmdlets. – jscott Jan 28 '17 at 01:43
  • Works just fine on Windows 7. – I say Reinstate Monica Jan 29 '17 at 20:51
  • 1
    This is an old post, but when I attempted to use this today I had an issue where if there's 2 accounts with the same name, but different domains, the SID will be duplicated since the translate as it is in this code only works on the username itself. I've posted another solution below that addresses this. – Daniel Mar 24 '23 at 21:00
1

@Ryan Bolger 's solution mostly works, however there's an issue where if there's 2 accounts with the same name, but different domains, the SID will be duplicated since the translate as it was only works on the username itself. Below is a modified version of their function that addresses this.

Function Get-LocalGroupMembers  {

[Cmdletbinding()] 
Param( 
    [Parameter(Mandatory=$true)]
    [string]$GroupName
)

[adsi]$adsiGroup = "WinNT://$($env:COMPUTERNAME)/$GroupName,group"

$Members = @()

$adsiGroup.Invoke('Members') | ForEach-Object{

    $username = $_.GetType().InvokeMember('Name','GetProperty',$null,$_,$null)
    $path = $_.GetType().InvokeMember('AdsPath','GetProperty',$null,$_,$null).Replace('WinNT://','')
    $class = $_.GetType().InvokeMember('Class','GetProperty',$null,$_,$null)
    $userObj = $null
    
    if ($path -notlike "*S-1-5*"){ #If the path does not contain a SID, then AD is reachable and we can translate successfully
        $Parts = $path.Split("/") 
        <#
            $Parts can look like:
            Local Account  - Domain, ComputerName, AccountName 
            Domain Account - Domain, AccountName 
        #>
        $Domain = $Parts[0]

        if ($Parts[1] -eq $env:COMPUTERNAME){ #Based on above comment, if arg 2 is the ComputerName, it's a local account
            $userObj = New-Object System.Security.Principal.NTAccount($username)

        }else{#Otherwise it's a domain account and we need to translate using the domain
            $userObj = New-Object System.Security.Principal.NTAccount($Domain, $username)
        }
        $sid = $userObj.Translate([System.Security.Principal.SecurityIdentifier])
    }else{ #Otherwise AD not reachable and the SID is just the username
        $sid = $username
    }

    $Members += [pscustomobject]@{
        Username = $username
        Type = $class
        SID = $sid
        Path = $path
    }
}   
return $Members
}
Daniel
  • 121
  • 5