1..2 | ForEach-Object { 'begin' } { 'process A' } { 'process B' } { 'end' }
begin
process A
process B
process A
process B
第一個腳本區塊一律會對應至 begin 區塊,最後一個區塊會對應至 end 區塊,而 之間的區塊全都對應至 process 區塊。
範例 10:針對每個管線專案執行多個腳本區塊
如先前範例所示,使用 Process 參數傳遞的多個腳本區塊會對應至 Begin 和 End 參數。 若要避免此對應,您必須提供 Begin 和 End 參數的明確值。
1..2 | ForEach-Object -Begin $null -Process { 'one' }, { 'two' }, { 'three' } -End $null
three
three
範例 11:以平行批次執行慢速腳本
此範例會執行腳本區塊,以評估字串並睡眠一秒。
$Message = "Output:"
1..8 | ForEach-Object -Parallel {
"$using:Message $_"
Start-Sleep 1
} -ThrottleLimit 4
Output: 1
Output: 2
Output: 3
Output: 4
Output: 5
Output: 6
Output: 7
Output: 8
ThrottleLimit參數值設定為 4,以便以四個批次處理輸入。
關鍵字 $using: 用來將 $Message 變數傳遞至每個平行腳本區塊。
範例 12:平行擷取記錄專案
此範例會從本機 Windows 電腦上的 5 個系統記錄擷取 50,000 個記錄專案。
$logNames = 'Security','Application','System','Windows PowerShell','Microsoft-Windows-Store/Operational'
$logEntries = $logNames | ForEach-Object -Parallel {
Get-WinEvent -LogName $_ -MaxEvents 10000
} -ThrottleLimit 5
$logEntries.Count
50000
Parallel 參數會針對每個輸入記錄名稱指定平行執行的指令碼區塊。 ThrottleLimit參數可確保所有五個腳本區塊都會同時執行。
範例 13:以作業方式平行執行
此範例會建立一個作業,以平行方式執行腳本區塊,一次兩個。
$job = 1..10 | ForEach-Object -Parallel {
"Output: $_"
Start-Sleep 1
} -ThrottleLimit 2 -AsJob
$job | Receive-Job -Wait
Output: 1
Output: 2
Output: 3
Output: 4
Output: 5
Output: 6
Output: 7
Output: 8
Output: 9
Output: 10
變數 $job 會接收收集輸出資料和監視執行中狀態的工作物件。
工作物件會使用Wait參數透過管線傳送至 Receive-Job ,它會將輸出串流至主控台,就像 ForEach-Object -Parallel 沒有AsJob一樣執行。
範例 14:使用執行緒安全變數參考
此範例會平行叫用腳本區塊,以收集唯一命名的 Process 物件。
$threadSafeDictionary = [System.Collections.Concurrent.ConcurrentDictionary[string,object]]::new()
Get-Process | ForEach-Object -Parallel {
$dict = $using:threadSafeDictionary
$dict.TryAdd($_.ProcessName, $_)
$threadSafeDictionary["pwsh"]
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
82 82.87 130.85 15.55 2808 2 pwsh
ConcurrentDictionary物件的單一實例會傳遞至每個腳本區塊來收集物件。 由於 ConcurrentDictionary 是安全線程,因此每個平行腳本都能夠安全地修改。 非安全線程的物件,例如 System.Collections.Generic.Dictionary,無法放心在此使用。
這個範例是 平行 參數的非常沒有效率的使用。 腳本只會將輸入物件新增至並行字典物件。 這很簡單,不值得在個別執行緒中叫用每個腳本的額外負荷。 在不使用平行交換器的情況下正常執行 ForEach-Object 會更有效率且更快速。 此範例僅供示範如何使用執行緒安全變數。
範例 15:使用平行執行撰寫錯誤
這個範例會以平行方式寫入錯誤資料流程,其中寫入錯誤的順序是隨機的。
1..3 | ForEach-Object -Parallel {
Write-Error "Error: $_"
Write-Error: Error: 1
Write-Error: Error: 3
Write-Error: Error: 2
範例 16:平行執行中終止錯誤
此範例示範一個平行執行的 scriptblock 中的終止錯誤。
1..5 | ForEach-Object -Parallel {
if ($_ -eq 3)
throw "Terminating Error: $_"
Write-Output "Output: $_"
Exception: Terminating Error: 3
Output: 1
Output: 4
Output: 2
Output: 5
Output: 3 永遠不會寫入,因為該反復專案的平行腳本區塊已終止。
即使使用 $using: 關鍵字,在案例中 Foreach-Object -Parallel也不支援PipelineVariable一般參數變數。
範例 17:在巢狀平行腳本 ScriptBlockSet 中傳遞變數
您可以在限定範圍的 scriptblock 之外 Foreach-Object -Parallel 建立變數,並在 scriptblock 內搭配 $using 關鍵字使用。
$test1 = 'TestA'
1..2 | Foreach-Object -Parallel {
$using:test1
TestA
TestA
# You CANNOT create a variable inside a scoped scriptblock
# to be used in a nested foreach parallel scriptblock.
$test1 = 'TestA'
1..2 | Foreach-Object -Parallel {
$using:test1
$test2 = 'TestB'
1..2 | Foreach-Object -Parallel {
$using:test2
Line |
2 | 1..2 | Foreach-Object -Parallel {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
| The value of the using variable '$using:test2' cannot be retrieved because it has not been set in the local session.
巢狀腳本區塊無法存取 $test2 變數,並擲回錯誤。
範例 18:建立多個平行執行腳本的作業
ThrottleLimit 參數會限制在每個 實例 ForEach-Object -Parallel 期間執行的平行腳本數目。 它不會限制使用 AsJob 參數時可建立的作業數目。 由於作業本身會同時執行,因此可以建立一些平行作業,每個作業都會執行到並行腳本區塊的節流限制數目。
$jobs = for ($i=0; $i -lt 10; $i++) {
1..10 | ForEach-Object -Parallel {
./RunMyScript.ps1
} -AsJob -ThrottleLimit 5
$jobs | Receive-Job -Wait
此範例會建立 10 個執行中的作業。 每個作業不會同時執行 5 個腳本。 同時執行的實例總數限制為 50 (10 個作業, 而 ThrottleLimit 為 5) 。
-ArgumentList
指定方法呼叫的引數陣列。 如需 ArgumentList行為的詳細資訊,請參閱 about_Splatting。
此參數是在 Windows PowerShell 3.0 引進。
Type:Object[]
Aliases:Args
Position:Named
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-AsJob
讓平行調用以 PowerShell 作業的形式執行。 會傳回單一工作物件,而不是執行中的腳本區塊的輸出。 工作物件包含每個執行之平行腳本區塊的子作業。 所有 PowerShell 作業 Cmdlet 都可以使用此工作物件來監視執行中狀態並擷取資料。
此參數是在 PowerShell 7.0 中引進的。
Type:SwitchParameter
Position:Named
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-Begin
指定在這個 Cmdlet 處理任何輸入物件之前執行的腳本區塊。 此腳本區塊只會針對整個管線執行一次。 如需 區塊的詳細資訊 begin ,請參閱 about_Functions。
Type:ScriptBlock
Position:Named
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-Confirm
在執行 Cmdlet 前提示您確認。
Type:SwitchParameter
Aliases:cf
Position:Named
Default value:False
Accept pipeline input:False
Accept wildcard characters:False
指定在這個 Cmdlet 處理所有輸入物件之後執行的腳本區塊。 此腳本區塊只會針對整個管線執行一次。 如需 區塊的詳細資訊 end ,請參閱 about_Functions。
Type:ScriptBlock
Position:Named
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-InputObject
指定輸入物件。 ForEach-Object 在每個輸入物件上執行腳本區塊或 operation 語句。 輸入包含物件的變數,或輸入可取得物件的命令或運算式。
當您搭配 使用InputObject參數搭配 ForEach-Object 時,會將 InputObject值視為單一物件,而不是將命令結果管線傳送至 ForEach-Object 。 即使值是命令結果的集合,例如 -InputObject (Get-Process) ,也是如此。
由於 InputObject 無法從物件的陣列或集合傳回個別屬性,因此,如果您用來 ForEach-Object 對定義屬性中具有特定值之物件的物件集合執行作業,請在 ForEach-Object 管線中使用,如本主題中的範例所示。
Type:PSObject
Position:Named
Default value:None
Accept pipeline input:True
Accept wildcard characters:False
-MemberName
指定要取得的屬性或要呼叫的方法。
允許萬用字元,但只有在產生的字串解析為唯一值時,才能運作。
例如,如果您執行 Get-Process | ForEach -MemberName *Name ,萬用字元模式會比對一個以上的成員,導致命令失敗。
此參數是在 Windows PowerShell 3.0 引進。
Type:String
Position:0
Default value:None
Accept pipeline input:False
Accept wildcard characters:True
-Parallel
指定要用於平行處理輸入物件的腳本區塊。 輸入描述操作的指令碼區塊。
此參數是在 PowerShell 7.0 中引進的。
Type:ScriptBlock
Position:Named
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-Process
指定在每個輸入物件上執行的操作。 此腳本區塊會針對管線中的每個物件執行。 如需 區塊的詳細資訊 process ,請參閱 about_Functions。
當您將多個腳本區塊提供給 Process 參數時,第一個腳本區塊一律會對應至 begin 區塊。 如果只有兩個腳本區塊,則第二個區塊會對應至 process 區塊。 如果有三個以上的腳本區塊,則第一個腳本區塊一律會對應至 begin 區塊,最後一個區塊會對應至 end 區塊,而兩者之間的區塊全都對應至 process 區塊。
Type:ScriptBlock[]
Position:0
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-RemainingScripts
指定 Process 參數未採用的所有腳本區塊。
此參數是在 Windows PowerShell 3.0 引進。
Type:ScriptBlock[]
Position:Named
Default value:None
Accept pipeline input:False
Accept wildcard characters:False
-ThrottleLimit
指定平行的腳本區塊數目。 輸入物件會遭到封鎖,直到執行中的腳本區塊計數低於 ThrottleLimit為止。 預設值是 5。
ThrottleLimit 參數會限制在每個 實例 ForEach-Object -Parallel 期間執行的平行腳本數目。 它不會限制使用 AsJob 參數時可建立的作業數目。 由於作業本身會同時執行,因此可以建立一些平行作業,每個作業都會執行到並行腳本區塊的節流限制數目。
此參數是在 PowerShell 7.0 中引進的。
Type:Int32
Position:Named
Default value:5
Accept pipeline input:False
Accept wildcard characters:False
-TimeoutSeconds
指定等候所有輸入平行處理的秒數。 在指定的逾時時間之後,所有執行中的腳本都會停止。 而且會忽略要處理的任何其餘輸入物件。 的 0 預設值會停用逾時,而且 ForEach-Object -Parallel 可以無限期執行。 在命令列中輸入Ctrl+C會停止執行 ForEach-Object -Parallel 中的命令。 此參數不能與 AsJob 參數一起使用。
此參數是在 PowerShell 7.0 中引進的。
Type:Int32
Position:Named
Default value:0
Accept pipeline input:False
Accept wildcard characters:False
-UseNewRunspace
讓平行調用為每個迴圈反復專案建立新的 Runspace,而不是從 Runspace 集區重複使用 Runspace。
此參數是在 PowerShell 7.1 中引進的
Type:SwitchParameter
Position:Named
Default value:False
Accept pipeline input:False
Accept wildcard characters:False
-WhatIf
顯示執行 Cmdlet 後會發生的情況。 Cmdlet 並不會執行。
Type:SwitchParameter
Aliases:wi
Position:Named
Default value:False
Accept pipeline input:False
Accept wildcard characters:False
PSObject
您可以使用管線將任何物件傳送至此 Cmdlet。
PSObject
此 Cmdlet 會傳回輸入所決定的物件。
PowerShell 包含下列的 ForEach-Object 別名:
所有平臺:
foreach
Cmdlet ForEach-Object 的運作方式與 Foreach 語句非常類似,不同之處在于您無法使用管線將輸入傳送至 Foreach 語句。 如需 Foreach 語句的詳細資訊,請參閱 about_Foreach。
從 PowerShell 4.0 開始, Where 已 ForEach 新增方法以搭配集合使用。 您可以在這裡深入瞭解這些新方法 about_arrays
使用 ForEach-Object -Parallel:
參數 ForEach-Object -Parallel 集會使用 PowerShell 的內部 API,在新 Runspace 中執行每個腳本區塊。 相較于以循序處理正常執行,這明顯比執行 ForEach-Object 額外負荷還要多。 相較于腳本區塊執行的工作,平行執行的額外負荷很小,請務必使用 Parallel 。 例如:
- 在多核心電腦上計算密集腳本
- 花費時間等候結果或執行檔案作業的腳本
使用 Parallel 參數可能會導致腳本執行速度比正常慢很多。 特別是平行腳本很簡單時。 使用 Parallel 進行實驗,以探索其可能有説明的位置。
以平行方式執行時,如果以 ScriptProperties 或 ScriptMethods 裝飾的物件是在與腳本原本附加至不同的 Runspace 中執行,則無法保證能夠正常運作。
無論實際叫用的位置為何,Scriptblock 調用一律會嘗試在其 主 Runspace 中執行。 不過, ForEach-Object -Parallel 會建立在使用後刪除的暫存 Runspace,因此腳本不會再執行 Runspace。
只要 主 Runspace 仍然存在,此行為就可以運作。 不過,如果腳本相依于只存在於呼叫端 Runspace 中的外部變數,而不是 主 Runspace,則可能無法取得所需的結果。
非終止錯誤會寫入 Cmdlet 錯誤資料流程,因為它們會在平行執行的 scriptblock 中發生。 因為平行 scriptblock 執行順序不具決定性,所以錯誤串流中出現錯誤的順序是隨機的。 同樣地,寫入至其他資料流程的訊息,例如警告、詳細資訊或資訊會以不確定的順序寫入這些資料流程。
終止錯誤,例如例外狀況,會終止其發生之 scriptblock 的個別平行實例。 一個 scriptblock 中的終止錯誤可能不會造成 Cmdlet 的 Foreach-Object 終止。 其他腳本區塊會以平行方式執行,除非它們也遇到終止錯誤,否則會繼續執行。 終止錯誤會以具有的 FullyQualifiedErrorIdPSTaskException 做為ErrorRecord寫入錯誤資料流程。
終止錯誤可以使用 PowerShell try/catch 或 trap 區塊轉換成非終止錯誤。
即使使用 $using: 關鍵字,在平行案例中也不支援PipelineVariable通用參數變數。
參數集會在 ForEach-Object -Parallel 不同的進程執行緒上平行執行腳本區塊。 $using:關鍵字允許將變數參考從 Cmdlet 調用執行緒傳遞至每個執行中的腳本區塊執行緒。 由於腳本區塊在不同的執行緒中執行,因此必須安全地使用以傳址方式傳遞的物件變數。 一般而言,從未變更的參考物件讀取是安全的。 但是,如果要修改物件狀態,則必須使用執行緒安全物件,例如 .NET System.Collection.Concurrent 類型 (請參閱範例 11) 。