我正在尝试编制一份有权访问我们组织中的一组计算机/服务器的群组列表,并参考 MSDN 许可证报告.. :-/
我的工作基于 Hey Scripting Guy 关于本地群组成员资格的博客文章:http://blogs.technet.com/b/heyscriptingguy/archive/2013/10/27/the-admin-s-first-steps-local-group-membership.aspx
但是,我需要在每个服务器上验证多个组中的成员。然后出现了一个尴尬的事情,我不记得以前见过:当向函数的参数部分添加其他参数时,无法获取任何组成员。
function Test-LocalSecurityGroups {
[CmdletBinding()]
param(
[parameter(
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[string[]]$ComputerName = $env:COMPUTERNAME,
[parameter(
ValueFromPipelineByPropertyName=$true)]
[string[]]$Group
)
BEGIN {
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ctype = [System.DirectoryServices.AccountManagement.ContextType]::Machine
}
PROCESS{
foreach ($Computer in $ComputerName) {
Write-Verbose "Connecting to $Computer"
$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='Group Name'; E={$group.Name}}, @{N='Domain'; E={$_.Context.Name}}, samaccountName
} # end foreach
} # end PROCESS
}
以下是一些不起作用的使用示例(根本没有返回任何结果):
PS D:\> Test-LocalSecurityGroups -ComputerName $env:COMPUTERNAME -Group "Administrator"
PS D:\>
PS D:\> $env:COMPUTERNAME, "Computer1" | Test-LocalSecurityGroups
PS D:\>
PS D:\> $env:COMPUTERNAME, "Computer1" | Test-LocalSecurityGroups -Group "Administrators"
PS D:\>
但是,这甚至没有对 Group 变量进行任何操作。如果我注释掉这部分:
[parameter(
ValueFromPipelineByPropertyName=$true)]
[string[]]$Group
)
它工作正常。那么,有人能向我解释一下,为什么会发生这种情况吗?我也有围绕整个功能的更大的框架,但是当它被隔离时,我遇到了同样的问题,所以我的结论是,要么是我忘记了 powershell 的一些可行的东西,要么是发生了一些奇怪的事情。
没有错误,用户列表只是空的。我在 PowerShell ISE 中运行它以及直接在 shell 中加载它时遇到了同样的问题(包括点源和将函数粘贴到 shell 中)。
另一种方法是使用两个单独的函数,然后在第三个函数中比较结果。但这真的不是一个好的解决方案,不是吗?:-p DRY FTW!
答案1
换句话说:$Group.Equals($group)
在PROCESS
块内,当您将对象分配GroupPrincipal
给时$group
,您实际上是在尝试覆盖现有的$Group
参数变量。
只需更改内联变量名称,并添加另一个循环来迭代每个组名称:
foreach ($Computer in $ComputerName) {
Write-Verbose "Connecting to $Computer"
$context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype, $Computer
$idtype = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
foreach($groupName in $Group)
{
$groupPrincipal = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($context, $idtype, $groupName)
$groupPrincipal.Members | select @{N='Server'; E={$computer}}, @{N='Group Name'; E={$groupPrincipal.Name}}, @{N='Domain'; E={$_.Context.Name}}, samaccountName
}
} # end foreach