Powershell

一對多 Powershell 腳本

  • August 18, 2013

我正在嘗試創建一個腳本以作為計劃任務執行,它將針對多個伺服器執行並檢索一些資訊。

首先,我通過使用 Get-ADComputer 查詢符合特定條件集的所有伺服器的 AD 來填充伺服器列表。

問題是,列表作為對象返回,然後我不能將其傳遞給 New-PSSession 列表。我嘗試通過執行以下操作將其轉換為逗號分隔的字元串:

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

但這仍然行不通。

另一種方法是遍歷列表並一次對每個伺服器執行各種命令,但我的偏好是避免這種情況並使用一對多遠端處理來執行它們。

**更新:**為了澄清我最終想要做的是 using -ComputerName $serverlist,所以我希望 $serverlist 是一個字元串而不是一個對象。

**更新2:**感謝所有建議。在它們和我原來的方法之間,我開始懷疑是否-ComputerName可以接受字元串變數?我在將電腦列表轉換為逗號分隔字元串方面取得了不同程度的成功,但無論我怎麼做,我總是得到無效的網路地址。

再解釋一下,如果你已經執行了,Get-ADComputer那麼你可能會得到一個對像數組或單個對象。

我假設您正在呼叫類似以下內容:

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

這將使所有電腦都以DC他們的名字命名。

因為您可能有一個數組(不止一個)或您使用ForEach-Objectcmdlet 處理的對象(也別名為%or foreach)是一個好方法。這基本上是為管道中的每條記錄執行一個腳本塊。但是,正如您所經歷的那樣,您從查詢中得到一個對象而不是一個字元串。因此,您只需選擇要使用的屬性。

例如,如果您使用:

$serverList[0] | Get-Member

您將獲得電腦對象的所有屬性。gm也是 的別名Get-Member。例如

PS> $伺服器列表

$$ 0 $$| 通用汽車

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除了創建與電腦的遠端會話之外,cmdlet 並沒有做太多的事情(必須啟用 PowerShell Remoting 才能支持此功能)。您將需要使用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附加到它們。

您還可以將任何命令包裝在一個函式中以執行單個命令。

希望能回答你的問題。

引用自:https://serverfault.com/questions/320305