1

I found this thread that offers two basic approaches to getting local group members.

This works for me in all versions of powershell, but depends on using the old NET command line utility.

function Get-LocalGroupMembers() {
  param ([string]$groupName = $(throw "Need a name") )
  $lines = net localgroup $groupName
  $found = $false
  for ($i = 0; $i -lt $lines.Length; $i++ ) {
    if ( $found ) {
      if ( -not $lines[$i].StartsWith("The command completed")) {
        $lines[$i]
      }
    } elseif ( $lines[$i] -match "^----" ) {
      $found = $true;
    }
  }
}

This works for me in PowerShell 2.0, but barfs in PS5.0 with Error while invoking GetType. Could not find member. It only barfs on some groups, including Administrators, which has me thinking it's some sort of security feature, like requiring elevated privileges to REALLY have admin rights in a script.

Function Get-LocalGroupMembers
{
    Param(
        [string]
        $server = "."
    )
    Try
    {
        $computer = [ADSI]"WinNT://$( $Server ),computer"
        $computer.psbase.children | 
            where { 
                $_.psbase.schemaClassName -eq 'group' 
            } |
                ForEach {
                    $GroupName = $_.Name.ToString()
                    $group =[ADSI]$_.psbase.Path
                    $group.psbase.Invoke("Members") |
                        foreach {
                            $memberName = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null) -replace "WinNT:", ""

                            $props = @{
                                "LocalGroup" = $GroupName
                                "MemberName" = $memberName
                            }

                            $obj = New-Object -TypeName psobject -Property $props
                            Write-Output $obj
                        } # foreach members
                } # foreach group
    }
    Catch
    {
        Throw
    }
}

I think I read somewhere that PS5.1 has a native CMDlet finally. But I can't depend on a particular version of PS, I need to support everything from PS2.0 in Win7 up. That said, is there a single version agnostic solution that doesn't depend on a command line utility kludge? Or do I need to have code that uses the old hack or the new CMDlet depending on PS version I am running on?

Gordon
  • 6,257
  • 6
  • 36
  • 89
  • 1
    Yes, pwsh 5.1 has `Get-LocalGroup` and `Get-LocalGroupMember`. You could `try { Get-LocalGroup...` and fall back to the raw `net` command when it is caught. Can you say more about which line presents the GetType() error message? – lit Sep 16 '18 at 22:18
  • @lit for clarity, `pwsh` refers to `pwsh.exe` which was introduced in `PowerShell Core 6.0`. People have nicknamed `Windows PowerShell` as `posh` for some time, however. – Maximilian Burszley Sep 17 '18 at 00:39
  • @OP: Why are you limiting yourself so much? Get WMF5.1 installed in your environment and stop worrying about backporting scripts and spend less time porting and more time writing. It isn't 5.1 that introduced what you're thinking of, either. `Get-LocalGroupMember` was introduced in 8.1/2012R2 – Maximilian Burszley Sep 17 '18 at 00:52
  • @TheIncorrigible1 I don't have that luxury, as my tool is used in offices where I don't control the IT infrastructure. It's frustrating, and I encourage customers to upgrade, but I can't enforce it, so I work around it. – Gordon Sep 17 '18 at 09:41

2 Answers2

0

So, I am having good luck with this solution.

$hostname = (Get-WmiObject -computerName:'.' -class:Win32_ComputerSystem).name 
$wmiQuery = Get-WmiObject -computerName:'.' -query:"SELECT * FROM Win32_GroupUser WHERE GroupComponent=`"Win32_Group.Domain='$Hostname',Name='$group'`"" 
if ($wmiQuery -ne $null) {  
    :searchLoop foreach ($item in $wmiQuery) {  
       if (((($item.PartComponent -split "\,")[1] -split "=")[1]).trim('"') -eq $user) {
           $localGroup = $true
           break :searchLoop
        }
    }  
 }

I'm not sure yet if I like that overly complex IF vs some variables, but the functionality is there and working across all versions of PS without resorting to command line kludges, which was the goal. Note that this just returns true if the user is a member of the group, which is all I need. The other code I posted would provide a list of members, which is the basis of doing a check, and I just hadn't modified it to show the real end goal, since the problem manifested without that.

Gordon
  • 6,257
  • 6
  • 36
  • 89
0

Instead this :

$memberName = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null) -replace "WinNT:", ""

You can try this :

$memberName = ([ADSI]$_).InvokeGet("Name")
keegzer
  • 383
  • 1
  • 4
  • 15