在 PowerShell 5.0 中打印本地组成员
Print Local Group Members in PowerShell 5.0
我使用以下代码来确定本地 Administrators 组的成员:
$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"
此代码适用于 PowerShell 2.0 - 4.0。但是,在装有 PowerShell 5.0 的 Windows 10 机器上,它出现故障。对于属于本地 Administrators 组的每个 local 帐户,它会抛出以下错误:
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
对于属于 Administrators 成员的域帐户,不会生成错误。
令我困惑的是GetType()
是object的一个成员(我手写命令),所以我不确定为什么会出错。
我查看了 PowerShell 5.0 的变更日志,但没有看到任何可以明显解释此行为的内容。
为什么会这样?是否有更好的方法在 PowerShell 5.0 中打印本地组的成员?
您可能想要 post 错误 here 因为有人可能有可用的解决方法。
运行 我自己解决了这个问题并找到了解决方法(在 windows 10 和 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"
Jamie 的回答非常适合您的具体问题,但我需要从成员那里获取多个属性。我发现您可以通过在针对 GetType
调用 InvokeMember
之前针对 Invoke
调用 Invoke
来解决此问题,而无需更改您的代码。请注意,在下面的代码中,GetType 后面不再有 ()
:
$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"
这是我的用例,它提供了有关群组成员的更多信息。由于使用 Resolve-DNS 命令,这确实需要 PowerShell 4.0:
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
}
不错!需要这个!
.net 方式也是 bypass:
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
我使用以下代码来确定本地 Administrators 组的成员:
$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"
此代码适用于 PowerShell 2.0 - 4.0。但是,在装有 PowerShell 5.0 的 Windows 10 机器上,它出现故障。对于属于本地 Administrators 组的每个 local 帐户,它会抛出以下错误:
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
对于属于 Administrators 成员的域帐户,不会生成错误。
令我困惑的是GetType()
是object的一个成员(我手写命令),所以我不确定为什么会出错。
我查看了 PowerShell 5.0 的变更日志,但没有看到任何可以明显解释此行为的内容。
为什么会这样?是否有更好的方法在 PowerShell 5.0 中打印本地组的成员?
您可能想要 post 错误 here 因为有人可能有可用的解决方法。
运行 我自己解决了这个问题并找到了解决方法(在 windows 10 和 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"
Jamie 的回答非常适合您的具体问题,但我需要从成员那里获取多个属性。我发现您可以通过在针对 GetType
调用 InvokeMember
之前针对 Invoke
调用 Invoke
来解决此问题,而无需更改您的代码。请注意,在下面的代码中,GetType 后面不再有 ()
:
$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"
这是我的用例,它提供了有关群组成员的更多信息。由于使用 Resolve-DNS 命令,这确实需要 PowerShell 4.0:
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
}
不错!需要这个!
.net 方式也是 bypass:
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