一对多 Powershell 脚本

一对多 Powershell 脚本

我正在尝试创建一个脚本作为计划任务运行,该脚本将针对多台服务器运行并检索一些信息。

首先,我使用 Get-ADComputer 查询 AD 中符合特定条件的所有服务器,从而填充服务器列表。

问题是,列表作为对象返回,我无法将其传递给 New-PSSession 列表。我尝试通过执行以下操作将其转换为逗号分隔的字符串:

foreach ($server in $serverlist) {$newlist += $server.Name + ","}

但这仍然不起作用。

另一种方法是遍历列表并一次对每个服务器运行各种命令,但我的偏好是避免这样做并使用一对多远程处理来运行它们。

更新:为了澄清我最终想要做的事情是使用-ComputerName $serverlist,所以我希望 $serverlist 是一个字符串而不是一个对象。

更新2:感谢大家的建议。在它们和我原来的方法之间,我开始怀疑是否-ComputerName可以接受字符串变量?我成功地将计算机列表转换为逗号分隔的字符串,但无论我怎么做,我总是得到无效的网络地址。

答案1

进一步解释一下,如果你已经执行,Get-ADComputer那么你可能会得到一个对象数组或一个对象。

我假设您正在调用以下内容:

$serverList = Get-ADComputer -LDAPFilter '(cn=*DC*)';

DC这将获得所有以他们名义登记的计算机。

因为您可能有一个数组(不止一个)或对象,所以使用 cmdlet ForEach-Object(也别名为%foreach)进行处理是一种很好的方法。这基本上是对管道中的每个记录执行一个脚本块。但是,正如您所经历的,您从查询中得到的是一个对象,而不是字符串。所以您只需选择一个要使用的属性。

例如如果你使用:

$serverList[0] | Get-Member

您将获得计算机对象的所有属性。gm也是的别名Get-Member。例如

PS> $serverList[0] | gm

TypeName: Microsoft.ActiveDirectory.Management.ADComputer

Name              MemberType            Definition
----              ----------            ----------
Contains          Method                bool Contains(string propertyName)
Equals            Method                bool Equals(System.Object obj)
GetEnumerator     Method                System.Collections.IDictionaryEnumerator GetEnumerator()
GetHashCode       Method                int GetHashCode()
GetType           Method                type GetType()
ToString          Method                string ToString()
Item              ParameterizedProperty Microsoft.ActiveDirectory.Management.ADPropertyValueCollection Item(string p...
DistinguishedName Property              System.String DistinguishedName {get;set;}
DNSHostName       Property              System.String DNSHostName {get;set;}
Enabled           Property              System.Boolean Enabled {get;set;}
Name              Property              System.String Name {get;}
ObjectClass       Property              System.String ObjectClass {get;set;}
ObjectGUID        Property              System.Nullable`1[[System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, ...
SamAccountName    Property              System.String SamAccountName {get;set;}
SID               Property              System.Security.Principal.SecurityIdentifier SID {get;set;}
UserPrincipalName Property              System.String UserPrincipalName {get;set;}

快速查看一下,您就会发现有一个 DNSHostName 属性。

因此,要执行命令,您可以使用以下命令:

$serverList = Get-ADComputer -LDAPFilter '(cn=*DC*)';
$serverList | ForEach-Object { New-PSSession -ComputerName $_.DNSHostName; }

但是我要指出的是,New-PSSession除了创建与计算机的远程会话(必须启用 PowerShell Remoting 才能支持此功能)之外,该 cmdlet 不会执行太多操作。您需要使用该Invoke-Commandcmdlet 从脚本执行某些操作。

示例 1:

$serverList = Get-ADComputer -LDAPFilter '(cn=*DC*)';
$serverList | ForEach-Object { New-PSSession -ComputerName $_.DNSHostName; } | ForEach-Object { Invoke-Command -Session $_ -ScriptBlock { #Execute commands here }; };

示例 2:

Get-ADComputer -LDAPFilter '(cn=*DC*)' | % { Invoke-Command -ComputerName $_.DNSHostName -ScriptBlock { #Execute commands here }; };

第二个示例优化了,New-PSSession因为如果您只是要调用Invoke-Command没有高级选项的,那么它实际上并不是必需的。

还要注意,没有必要将结果存储在变量中,只有在执行时间很长并且需要多次使用它时才Get-ADComputer会这样做。Get-ADComputer

$_一个管道变量,它成为当前管道中的任何对象。

更新

具体来说,要Invoke-Command对多台计算机执行相同的命令,您可以使用参数-ComputerName来提供一个字符串数组。(这可以通过查看帮助来了解,即-ComputerName <String[]>。并非所有命令都是这种情况)。

如上所述,输出是一个对象。因此将构造Get-ADComputer与参数兼容的字符串数组。-ComputerName

$serverList = @();
Get-ADComputer -LDAPFilter '(cn=*DC*)' | % { $serverList += $_.DNSHostName; }

基本上,这会创建一个新数组并将每台计算机的 DNS 主机名添加到其中,但最终会得到string[]。然后您可以使用:

Invoke-Command -ComputerName $serverList -ScriptBlock { #Execute commands here };

不过还要注意,虽然表面上看起来您只执行了一条命令,但实际上它几乎总是多个 PowerShell cmdlet。例如,命令管道后面附加了一个静默| Out-Host

您还可以将任何命令包装在函数中以执行单个命令。

希望这能回答你的问题。

答案2

powershell 上的每个结果都是一个 .Net 对象。

当您在 powershell 中得到像您这样的结果 (一个对象) 并且需要一个字符串进行搜索或在另一个命令中使用时,您可以将结果 (对象) 通过管道传输到 cmdlet Out-String。或者,您可以使用Out-File

如果您想要更改输出中的某些内容,您可以将其与其他 cmdlet(如 Format-*、、等)结合Format-Table使用Format-List

因此,当你获取一个对象并且需要一个字符串时,请使用如下方法:

Command-Let | Out-String

或者

Command-Let | Format-Custom (parameters) | Out-String

答案3

我无法访问 AD cmdlet,因此只能在需要对象作为字符串时提供我以前做过的事情。

我在 MSSQLTips.com 上写了一篇关于使用 SQLPS 备份数据库的技巧。所以我基本上查询了 SQLPS 以获取数据库的名称,然后将其传递给命令BACKUP,该命令必须将名称视为字符串,而不是对象类型。你可以看到它这里如果你想。

如果您将$serverlist传递给Get-Member,请查看是否有ToString()方法。我认为此方法适用于大多数 System object 类型。如果您确实看到了它,那么您可以这样尝试您的命令:


$serverlist | foreach {$_.ToString()} | foreach {New-PSSession -computer $_}

相关内容