Print Local Group Members in PowerShell 5.0

I use the following code to determine the members of the local Administrators group:

$obj_group = [ADSI]"WinNT://localhost/Administrators,group" $members=@ ($obj_group.Invoke("Members"))|foreach{$_.GetType().InvokeMember("Name","GetProperty",$null,$_,$null)} Write-Output "Current local Administrators: $members" 

This code works in PowerShell 2.0 - 4.0. However, on my Windows 10 computer with PowerShell 5.0 it breaks. For each local account that is a member of the local Administrators group, it generates the following error:

 Error while invoking GetType. Could not find member. At line:2 char:54 + ... "))|foreach{$_.GetType().InvokeMember("Name","GetProperty",$null,$_,$ ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : OperationStopped: (:) [], MissingMemberException + FullyQualifiedErrorId : System.MissingMemberException 

For domain accounts that are members of Administrators, an error is not generated.

What puzzles me is that GetType() is a member of the object (I followed the command), so I'm not sure why this is a mistake.

I looked through the change log for PowerShell 5.0 and did not see anything that would obviously explain this behavior.

Why is this happening? If there is a better way to print local group members in PowerShell 5.0?

+6
source share
4 answers

I looked for this problem myself and realized a workaround (checked in windows 10 and 8.1)

 $obj_group = [ADSI]"WinNT://localhost/Administrators,group" $members= @($obj_group.psbase.Invoke("Members")) | foreach{([ADSI]$_).InvokeGet("Name")} Write-Output "Current local Administrators: $members" 
+10
source

Jamie's answer was perfect for your specific problem, but I need to get some properties from the participants. I found that you can solve this problem without changing any other code while calling Invoke against GetType before InvokeMember against it. Note that GetType does not have () after it in the code below:

 $obj_group = [ADSI]"WinNT://localhost/Administrators,group" $members=@ ($obj_group.Invoke("Members"))|foreach{$_.GetType.Invoke().InvokeMember("Name","GetProperty",$null,$_,$null)} Write-Output "Current local Administrators: $members" 

This was my use case, which contains additional information about the members of the group. This requires PowerShell 4.0 due to the use of the Resolve-DNS command:

 function Get-LocalGroupMembers { <# .Synopsis Get the group membership of a local group on the local or a remote computer .EXAMPLE Defaults to collecting the members of the local Administrators group PS C:\> Get-LocalGroupMembers | ft -AutoSize ComputerName ParentGroup Nesting Name Domain Class ------------ ----------- ------- ---- ------ ----- EricsComputer 0 Administrator EricsComp User EricsComputer 0 eric EricsComp User EricsComputer 0 Domain Admins DomainName Group .EXAMPLE Query a remote computer (that is known not to respond to a ping) and a targeted group PS C:\> Get-LocalGroupMembers -computerName EricsComputer -localgroupName Users -pingToEstablishUpDown $false ComputerName ParentGroup Nesting Name Domain Class ------------ ----------- ------- ---- ------ ----- EricsComputer 0 SomeOtherGuy EricsComp User .NOTES The ParentGroup and Nesting attributes in the output are present to allow the output of this function to be combined with the output of Get-ADNestedGroupMembers. They serve no purpose otherwise. #> Param( $computerName = $env:computername, $localgroupName = "Administrators", $pingToEstablishUpDown = $true ) $requestedComputerName = $computerName if ($computername = Resolve-DnsName $computername) { $computername = ($computername | where querytype -eq A).Name if ($computername -ne $requestedComputerName) { Write-Warning "Using name $computerName for $requestedComputerName" } } else { Write-Warning "Unable to resolve $requestedComputerName in DNS" return "" | select @{label="ComputerName";Expression={$requestedComputerName}}, @{label="ParentGroup";Expression={""}}, @{label="Nesting";Expression={""}}, @{Label="Name";Expression={"ComputerName did not resolve in DNS"}}, @{Label="Domain";Expression={"ComputerName did not resolve in DNS"}}, @{Label="Class";Expression={"ComputerName did not resolve in DNS"}} } if ($pingToEstablishUpDown) { if (-not (Test-Connection -count 1 $computerName)) { Write-Warning "Unable to ping $computerName, aborting ADSI connection attempt" return "" | select @{label="ComputerName";Expression={$requestedComputerName}}, @{label="ParentGroup";Expression={""}}, @{label="Nesting";Expression={""}}, @{Label="Name";Expression={"Not available to query"}}, @{Label="Domain";Expression={"Not available to query"}}, @{Label="Class";Expression={"Not available to query"}} } } try { if([ADSI]::Exists("WinNT://$computerName/$localGroupName,group")) { $group = [ADSI]("WinNT://$computerName/$localGroupName,group") $members = @() $Group.Members() | foreach { $AdsPath = $_.GetType.Invoke().InvokeMember("Adspath", 'GetProperty', $null, $_, $null) # Domain members will have an ADSPath like WinNT://DomainName/UserName. # Local accounts will have a value like WinNT://DomainName/ComputerName/UserName. $a = $AdsPath.split('/',[StringSplitOptions]::RemoveEmptyEntries) $name = $a[-1] $domain = $a[-2] $class = $_.GetType.Invoke().InvokeMember("Class", 'GetProperty', $null, $_, $null) $members += "" | select @{label="ComputerName";Expression={$computerName}}, @{label="ParentGroup";Expression={""}}, @{label="Nesting";Expression={0}}, @{Label="Name";Expression={$name}}, @{Label="Domain";Expression={$domain}}, @{Label="Class";Expression={$class}} } } else { Write-Warning "Local group '$localGroupName' doesn't exist on computer '$computerName'" } } catch { Write-Warning "Unable to connect to computer $computerName with ADSI" return $false } return ,$members } 
+2
source

You might want to post an error here, as someone might have a workaround.

+1
source

Nice! It is necessary!

The .net path was also a workaround ( http://blogs.technet.com/b/heyscriptingguy/archive/2013/10/27/the-admin-s-first-steps-local-group-membership.aspx )

 Add-Type -AssemblyName System.DirectoryServices.AccountManagement $ctype = [System.DirectoryServices.AccountManagement.ContextType]::Machine $computer = $env:COMPUTERNAME $context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype, $computer $idtype = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName $group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($context, $idtype, 'Administrators') $group.Members | select @{N='Server'; E={$computer}}, @{N='Domain'; E={$_.Context.Name}}, samaccountName 
+1
source

All Articles