透過 Windows PowerShell 使用一對多遠端
一對多遠端可讓您將單一命令平行傳送至多部電腦。 每部電腦將執行所傳輸的命令、將結果序列化為 XML,然後將這些結果傳輸回電腦。 電腦接著會將 XML 還原序列化為物件,並將其置於 Windows PowerShell 管線。 執行此操作時,多個屬性會新增至每個物件,包括 PSComputerName 屬性,指出每個結果源自的電腦。 該屬性可讓您根據電腦名稱排序、分組和篩選。
您可以透過兩種不同的技術來使用一對多遠端:
- Invoke-Command –ComputerName name1,name2 –ScriptBlock { 命令 }。 這項技術會將指令碼區塊中包含的命令傳送至所列出的電腦。 這項技術適用於傳送一或兩個命令,而多個命令會以分號分隔。
- Invoke-Command –ComputerName name1,name2 –FilePath 路徑。 這項技術會將 .ps1 副檔名的指令碼檔案內容傳送至所列出的檔案。 本機電腦會開啟檔案並讀取其內容。 不過,遠端電腦無須有對檔案的直接存取。 這項電腦適用於傳送大型命令檔案,例如完整的指令碼。
注意
在指令碼區塊內 (包括對 –ScriptBlock 參數提供的指令碼區塊),您可以使用分號來分隔多個命令。 例如,{ Get-Service ; Get-Process }
將執行 Get-Service,然後執行 Get-Process。
節流
為了協助管理本機電腦上的資源,PowerShell 包含依據命令截流功能,可讓您限制每個命令建立的並行遠端連線數目。 根據預設,Windows PowerShell 一次僅能連線至 32 部電腦。 如果您列出大於 32 部電腦,則其他電腦的連線將排入佇列。 第一批次的部分電腦工作模式完成並傳回結果之後,將會起始下一個批次中的電腦連線。
您可以使用 Invoke-Command 的 –ThrottleLimit 參數來更改此行為。 提高數目不會在遠端電腦上增加額外的負載。 不過,會在叫用 Invoke-Command 的電腦上增加額外的負載。 這也會利用更多頻寬。 每個並行連線基本上都是 Windows PowerShell 的執行緒。 因此,提高電腦數目會耗用本機電腦上的記憶體和處理器速度。
傳遞值
指令碼區塊或檔案內容會以常值文字形式傳輸至原樣執行這些項目的遠端電腦。 電腦不會剖析執行 Invoke-Command 的指令碼區塊或檔案。 請考慮下列命力範例:
$var = 'BITS'
Invoke-Command –ScriptBlock { Get-Service –Name $var } –Computer LON-DC1
在此案例中,$var
變數是在本機電腦上設定,而非包含於要在 LON-DC1 上執行的指令碼區塊中。 換言之,$var
不會在 PowerShell 遠端工作模式中定義或設定為 LON-DC1,這是系統管理員因不熟悉 Windows PowerShell 而經常造成的常見錯誤。
在本機或遠端執行命令
請密切注意,指令碼區塊中以括弧刮住的命令,這些命令會傳遞至遠端電腦。 請記住,本機電腦不會處理指令碼區塊內容,僅會將其傳遞至遠端電腦。 例如,請考量下列命令:
Invoke-Command –ScriptBlock { Do-Something –Credential (Get-Credential) } -ComputerName LON-DC1
此命令將在遠端電腦上執行 Get-Credential Cmdlet。 如果您嘗試在本機電腦上執行 Get-Credential,則將使用圖形化對話方塊來提示輸入認證。
問題:該命令在遠端電腦上執行時仍會運作嗎? 例如,如果您在 100 部遠端電腦上執行上述命令,系統會提示輸入 100 個認證嗎?
現在,請考慮此修改版的命令:
Invoke-Command –ScriptBlock { Param($c) Do-Something –Credential $c }
-ComputerName LON-DC1
-ArgumentList (Get-Credential)
此命令會在本機電腦上執行 Get-Credential 且僅執行一次。 產生的物件會傳遞至指令碼區塊的 $c
參數,讓每部電腦可以使用相同的認證。
這些範例說明謹慎撰寫遠端命令的重要性。 透過同時在遠端和本機執行命令,您可以各種實用的目標。
持續性
使用這裡所述的技術,每次使用 Invoke-Command 時,遠端電腦會建立新的 wsmprovhost 處理程序並執行命令。 接著會傳回結果並關閉該 Windows PowerShell 執行個體。 即使對同一部電腦執行,每個後續 Invoke-Command 都如同於開啟新的 Windows PowerShell 視窗。 除非您將工作儲存至磁碟或其他永續性儲存體,否則先前工作模式完成的任何工作都不會存在。 例如,請考量下列命令:
Invoke-Command –ComputerName LON-DC1 –ScriptBlock { $x = 'BITS' }
Invoke-Command –ComputerName LON-DC1 –ScriptBlock { Get-Service –Name $x }
在此範例中,Get-Service 會失敗,因為其會相依於先前 wsmprovhost 處理程序中建立的變數值。 Invoke-Command 叫用的第一個指令碼完成時,其變數會從記憶體中清除。 若要解決此問題,您可以在遠端電腦上建立 wsmprovhost 處理程序,如此便可成功將後續命令傳送至其中。
多個電腦名稱
Invoke-Command 的 –ComputerName 參數可以接受字串物件的集合作為電腦名稱。 下列清單描述可用於建立這類集合的不同技術:
- -ComputerName ONE,TWO,THREE。 電腦名稱的靜態、逗點分隔清單。
- -ComputerName (Get-Content Names.txt)。 從名為 Names.txt 的文字檔讀取名稱,假設檔案每行包含一個電腦名稱。
- -ComputerName (Import-Csv Computers.csv | Select –ExpandProperty Computer)。 讀取名為 Computers.csv 的逗點分隔值 (CSV) 檔案,並包括含有電腦名稱的名為 Computer 資料行。
- -ComputerName (Get-ADComputer –Filter * | Select –ExpandProperty Name)。 查詢 AD DS 中每個電腦物件,這可能在大型網域中需要大量時間。
使用電腦名稱時的常見錯誤
請留意指定電腦名稱的位置。 例如,檢閱下列命令:
Invoke-Command –ScriptBlock { Get-Service –ComputerName ONE,TWO }
此命令不會提供 Invoke-Command 的 –ComputerName 參數。 因此,命令會在本機電腦上執行。 本機電腦將對名為 ONE 和 TWO 的目標電腦執行 Get-Service。 將會使用 Get-Service 使用的通訊協定,而非 Windows PowerShell 遠端。 請比較此操作和下列命令:
Invoke-Command –ScriptBlock { Get-Service } –ComputerName ONE,TWO
此命令將使用 Windows PowerShell 遠端來連線至名為 ONE 和 TWO 的電腦。 每部電腦會在本機執行 Get-Service,並使用遠端傳回結果。
若為互動式更高的 Windows PowerShell 遠端情況,您可以個別時體的形式管理個別工作階段。 若要如此操作,您必須先使用 New-PSSession 命令來建立工作模式。 使用 New-PSSession 命令的優點是工作階段會在多個 Invoke-Command 執行個體中保存,讓您將變數和物件傳遞至指令碼中的其他命令。 您可以使用 New-PSSession 命令並將其指派給變數,來建立持續性工作階段。 然後,您稍後可以使用 Invoke-Command 命令來參考變數。 完成時,您可以使用 Remove-PSSession 命令來關閉持續性工作階段。