ForEach-Object (Microsoft.PowerShell.Core)
ForEach-Object
- โมดูล :
- Microsoft.PowerShell.Core
ดำเนินการกับแต่ละรายการในคอลเลกชันของออบเจ็กต์อินพุต
ไวยากรณ์
ForEach-Object
[-InputObject <PSObject>]
[-Begin <ScriptBlock>]
[-Process] <ScriptBlock[]>
[-End <ScriptBlock>]
[-RemainingScripts <ScriptBlock[]>]
[-WhatIf]
[-Confirm]
[<CommonParameters>]ForEach-Object
[-InputObject <PSObject>]
[-MemberName] <String>
[-ArgumentList <Object[]>]
[-WhatIf]
[-Confirm]
[<CommonParameters>]ForEach-Object
-Parallel <scriptblock>
[-InputObject <psobject>]
[-ThrottleLimit <int>]
[-TimeoutSeconds <int>]
[-AsJob]
[-UseNewRunspace]
[-WhatIf]
[-Confirm]
[<CommonParameters>]คำอธิบาย
cmdlet ForEach-Object ทำการดำเนินการกับแต่ละรายการในคอลเลกชันของวัตถุอินพุต ออบเจ็กต์อินพุตสามารถไปป์ไปยัง cmdlet หรือระบุโดยใช้พารามิเตอร์ InputObject
เริ่มต้นใน Windows PowerShell 3.0 มีสองวิธีในการสร้างคำสั่ง ForEach-Object
บล็อกสคริปต์ คุณสามารถใช้บล็อกสคริปต์เพื่อระบุการดำเนินการ ภายในบล็อกสคริปต์ ให้ใช้ตัวแปร
$_เพื่อแสดงอ็อบเจ็กต์ปัจจุบัน บล็อกสคริปต์คือค่าของพารามิเตอร์ กระบวนการ บล็อกสคริปต์สามารถมีสคริปต์ PowerShell ใดก็ได้ตัวอย่างเช่น คำสั่งต่อไปนี้ได้รับค่าของคุณสมบัติ ProcessName ของแต่ละกระบวนการบนคอมพิวเตอร์
Get-Process | ForEach-Object {$_.ProcessName}ForEach-Objectรองรับบล็อกbegin,processและendตามที่อธิบายไว้ใน about_functionsบันทึก
บล็อกสคริปต์ทำงานในขอบเขตของผู้โทร ดังนั้น บล็อกสามารถเข้าถึงตัวแปรในขอบเขตนั้น และสามารถสร้างตัวแปรใหม่ที่ยังคงอยู่ในขอบเขตนั้นหลังจาก cmdlet เสร็จสมบูรณ์
คำชี้แจงการดำเนินการ คุณยังสามารถเขียนคำสั่งการดำเนินการได้ ซึ่งเหมือนกับภาษาธรรมชาติมากกว่า คุณสามารถใช้คำสั่งการดำเนินการเพื่อระบุค่าคุณสมบัติหรือเรียกเมธอดได้ คำสั่งการดำเนินการถูกนำมาใช้ใน Windows PowerShell 3.0
ตัวอย่างเช่น คำสั่งต่อไปนี้ยังได้รับค่าของคุณสมบัติ ProcessName ของแต่ละกระบวนการบนคอมพิวเตอร์
Get-Process | ForEach-Object ProcessNameบล็อกสคริปต์ที่ทำงานแบบขนาน ตั้งแต่ PowerShell 7.0 เป็นต้นไป ชุดพารามิเตอร์ที่สามจะพร้อมใช้งานซึ่งจะเรียกใช้แต่ละบล็อกสคริปต์แบบขนาน พารามิเตอร์ ThrottleLimit จะจำกัดจำนวนสคริปต์แบบขนานที่ทำงานในแต่ละครั้ง เหมือนเมื่อก่อน ให้ใช้ตัวแปร
$_เพื่อแสดงออบเจ็กต์อินพุตปัจจุบันในบล็อกสคริปต์ ใช้คีย์เวิร์ด$using:เพื่อส่งผ่านการอ้างอิงตัวแปรไปยังสคริปต์ที่กำลังทำงานอยู่ใน PowerShell 7 รันสเปซใหม่จะถูกสร้างขึ้นสำหรับการวนซ้ำแต่ละครั้งเพื่อให้แน่ใจว่ามีการแยกสูงสุด นี่อาจเป็นการกระทบต่อประสิทธิภาพและทรัพยากรจำนวนมาก หากงานที่คุณกำลังทำมีขนาดเล็กเมื่อเทียบกับการสร้างรันสเปซใหม่ หรือหากมีการวนซ้ำหลายครั้งเพื่อดำเนินงานที่สำคัญ ใน PowerShell 7.1 รันสเปซจากพูลรันสเปซจะถูกนำมาใช้ซ้ำตามค่าเริ่มต้น พารามิเตอร์ ThrottleLimit จะกำหนดขนาดพูลรันสเปซ ขนาดพูลรันสเปซเริ่มต้นคือ 5 คุณยังคงสามารถสร้างรันสเปซใหม่สำหรับการวนซ้ำแต่ละครั้งได้โดยใช้สวิตช์ UseNewRunspace
ตามค่าเริ่มต้น scriptblock แบบขนานจะใช้ไดเร็กทอรีการทำงานปัจจุบันของผู้เรียกที่เริ่มงานแบบขนาน
สำหรับข้อมูลเพิ่มเติม ให้ดูส่วนหมายเหตุของบทความนี้
ตัวอย่าง
ตัวอย่างที่ 1: หารจำนวนเต็มในอาร์เรย์
ตัวอย่างนี้ใช้อาร์เรย์ของจำนวนเต็มสามจำนวนแล้วหารแต่ละจำนวนด้วย 1024
30000, 56798, 12432 | ForEach-Object -Process {$_/1024}
29.296875
55.466796875
12.140625ตัวอย่างที่ 2: รับความยาวของไฟล์ทั้งหมดในไดเร็กทอรี
ตัวอย่างนี้ประมวลผลไฟล์และไดเรกทอรีในไดเรกทอรีการติดตั้ง PowerShell $PSHOME
Get-ChildItem $PSHOME |
ForEach-Object -Process {if (!$_.PSIsContainer) {$_.Name; $_.Length / 1024; " " }}หากวัตถุไม่ใช่ไดเร็กทอรี บล็อกสคริปต์จะได้รับชื่อของไฟล์ หารค่าของคุณสมบัติ Length ด้วย 1,024 และเพิ่มช่องว่าง (" ") เพื่อแยกไฟล์ออกจากไดเร็กทอรีถัดไป รายการ. cmdlet ใช้คุณสมบัติ PSISContainer เพื่อตรวจสอบว่าวัตถุเป็นไดเรกทอรีหรือไม่
ตัวอย่างที่ 3: ดำเนินการกับเหตุการณ์ระบบล่าสุด
ตัวอย่างนี้เขียนเหตุการณ์ล่าสุด 1,000 เหตุการณ์จากบันทึกเหตุการณ์ของระบบไปยังไฟล์ข้อความ เวลาปัจจุบันจะแสดงก่อนและหลังการประมวลผลเหตุการณ์
Get-EventLog -LogName System -Newest 1000 |
ForEach-Object -Begin {Get-Date} -Process {
Out-File -FilePath Events.txt -Append -InputObject $_.Message
} -End {Get-Date}Get-EventLog รับเหตุการณ์ล่าสุด 1,000 เหตุการณ์จากบันทึกเหตุการณ์ของระบบและไปป์ไปยัง ForEach-Object cmdlet พารามิเตอร์ เริ่มต้น จะแสดงวันที่และเวลาปัจจุบัน ถัดไป พารามิเตอร์ กระบวนการ จะใช้ cmdlet Out-File เพื่อสร้างไฟล์ข้อความที่ชื่อ events.txt และจัดเก็บคุณสมบัติข้อความของแต่ละเหตุการณ์ในไฟล์นั้น สุดท้าย พารามิเตอร์ End ใช้เพื่อแสดงวันที่และเวลาหลังจากการประมวลผลทั้งหมดเสร็จสิ้น
ตัวอย่างที่ 4: เปลี่ยนค่าของคีย์รีจิสทรี
ตัวอย่างนี้เปลี่ยนค่าของรายการรีจิสทรี RemotePath ในคีย์ย่อยทั้งหมดภายใต้คีย์ HKCU:\Network เป็นข้อความตัวพิมพ์ใหญ่
Get-ItemProperty -Path HKCU:\Network\* |
ForEach-Object {
Set-ItemProperty -Path $_.PSPath -Name RemotePath -Value $_.RemotePath.ToUpper()
}คุณสามารถใช้รูปแบบนี้เพื่อเปลี่ยนแบบฟอร์มหรือเนื้อหาของค่ารายการรีจิสทรี
คีย์ย่อยแต่ละรายการในคีย์ เครือข่าย แสดงถึงไดรฟ์เครือข่ายที่แมปซึ่งจะเชื่อมต่อใหม่เมื่อลงชื่อเข้าใช้ รายการ RemotePath ประกอบด้วยเส้นทาง UNC ของไดรฟ์ที่เชื่อมต่อ ตัวอย่างเช่น หากคุณแมปไดรฟ์ E: กับ \\Server\Share คีย์ย่อย E จะถูกสร้างขึ้นใน HKCU:\ เครือข่าย ที่มีค่ารีจิสทรี RemotePath ตั้งค่าเป็น \\Server\Share
คำสั่งใช้ Get-ItemProperty cmdlet เพื่อรับคีย์ย่อยทั้งหมดของคีย์ เครือข่าย และ cmdlet Set-ItemProperty เพื่อเปลี่ยนค่าของ รายการรีจิสทรี RemotePath ในแต่ละคีย์ ในคำสั่ง Set-ItemProperty เส้นทางคือค่าของคุณสมบัติ PSPath ของคีย์รีจิสทรี นี่คือคุณสมบัติของวัตถุ Microsoft .NET Framework ที่แสดงถึงคีย์รีจิสทรี ไม่ใช่รายการรีจิสทรี คำสั่งใช้เมธอด ToUpper() ของค่า RemotePath ซึ่งเป็นสตริง REG_SZ
เนื่องจาก Set-ItemProperty กำลังเปลี่ยนแปลงคุณสมบัติของแต่ละคีย์ จึงจำเป็นต้องมี cmdlet ForEach-Object เพื่อเข้าถึงคุณสมบัติ
ตัวอย่างที่ 5: ใช้ตัวแปรอัตโนมัติ $null
ตัวอย่างนี้แสดงผลของการไพพ์ตัวแปรอัตโนมัติ $null ไปยัง ForEach-Object cmdlet
1, 2, $null, 4 | ForEach-Object {"Hello"}
Hello
Hello
Hello
Hello
เนื่องจาก PowerShell ถือว่า $null เป็นตัวยึดตำแหน่งที่ชัดเจน cmdlet ForEach-Object จะสร้างค่าสำหรับ $null เช่นเดียวกับที่ทำกับวัตถุอื่น ๆ ที่ไปป์ มัน.
ตัวอย่างที่ 6: รับค่าคุณสมบัติ
ตัวอย่างนี้รับค่าของคุณสมบัติ Path ของโมดูล PowerShell ที่ติดตั้งทั้งหมดโดยใช้พารามิเตอร์ MemberName ของ cmdlet ForEach-Object
Get-Module -ListAvailable | ForEach-Object -MemberName Path
Get-Module -ListAvailable | Foreach Pathคำสั่งที่สองเทียบเท่ากับคำสั่งแรก โดยจะใช้นามแฝง Foreach ของ cmdlet ForEach-Object และละเว้นชื่อของพารามิเตอร์ MemberName ซึ่งเป็นทางเลือก
ForEach-Object cmdlet มีประโยชน์ในการรับค่าคุณสมบัติ เนื่องจากได้รับค่าโดยไม่ต้องเปลี่ยนประเภท ต่างจาก cmdlet Format หรือ Select-Object cmdlet ซึ่งเปลี่ยนประเภทค่าคุณสมบัติ
ตัวอย่างที่ 7: แยกชื่อโมดูลออกเป็นชื่อส่วนประกอบ
ตัวอย่างนี้แสดงสามวิธีในการแบ่งชื่อโมดูลที่คั่นด้วยจุดสองชื่อออกเป็นชื่อส่วนประกอบ คำสั่งเรียกเมธอด Split ของสตริง คำสั่งทั้งสามใช้ไวยากรณ์ต่างกัน แต่เทียบเท่าและเปลี่ยนกันได้ ผลลัพธ์จะเหมือนกันสำหรับทั้งสามกรณี
"Microsoft.PowerShell.Core", "Microsoft.PowerShell.Host" |
ForEach-Object {$_.Split(".")}
"Microsoft.PowerShell.Core", "Microsoft.PowerShell.Host" |
ForEach-Object -MemberName Split -ArgumentList "."
"Microsoft.PowerShell.Core", "Microsoft.PowerShell.Host" |
Foreach Split "."
Microsoft
PowerShell
Core
Microsoft
PowerShell
Hostคำสั่งแรกใช้ไวยากรณ์แบบดั้งเดิม ซึ่งรวมถึงบล็อกสคริปต์และตัวดำเนินการอ็อบเจ็กต์ปัจจุบัน $_ ใช้ไวยากรณ์จุดเพื่อระบุวิธีการและวงเล็บเพื่อล้อมรอบอาร์กิวเมนต์ตัวคั่น
คำสั่งที่สองใช้พารามิเตอร์ MemberName เพื่อระบุวิธี Split และใช้พารามิเตอร์ ArgumentList เพื่อระบุจุด (. ) เป็นตัวคั่นแยก
คำสั่งที่สามใช้นามแฝง Foreach ของ ForEach-Object cmdlet และละเว้นชื่อของ MemberName และ ArgumentList พารามิเตอร์ซึ่งเป็นทางเลือก
ตัวอย่างที่ 8: การใช้ ForEach-Object กับสองบล็อกสคริปต์
ในตัวอย่างนี้ เราส่งบล็อกสคริปต์สองบล็อกในตำแหน่ง บล็อกสคริปต์ทั้งหมดเชื่อมโยงกับพารามิเตอร์ กระบวนการ อย่างไรก็ตาม สิ่งเหล่านี้จะถือว่าถูกส่งผ่านไปยังพารามิเตอร์ เริ่มต้น และ กระบวนการ
1..2 | ForEach-Object { 'begin' } { 'process' }
begin
process
processตัวอย่างที่ 9: การใช้ ForEach-Object กับบล็อกสคริปต์มากกว่าสองบล็อก
ในตัวอย่างนี้ เราส่งบล็อกสคริปต์สี่บล็อกตามตำแหน่ง บล็อกสคริปต์ทั้งหมดเชื่อมโยงกับพารามิเตอร์ กระบวนการ อย่างไรก็ตาม สิ่งเหล่านี้จะถือว่าถูกส่งผ่านไปยังพารามิเตอร์ เริ่มต้น, กระบวนการ และ สิ้นสุด
1..2 | ForEach-Object { 'begin' } { 'process A' } { 'process B' } { 'end' }
begin
process A
process B
process A
process B
endบันทึก
บล็อกสคริปต์แรกจะถูกแมปกับบล็อก เริ่มต้น เสมอ บล็อกสุดท้ายจะถูกแมปกับบล็อก สิ้นสุด และบล็อกกลางสองบล็อกจะถูกแมปกับ กระบวนการ บล็อก
ตัวอย่างที่ 10: เรียกใช้บล็อกสคริปต์หลายบล็อกสำหรับแต่ละรายการไปป์ไลน์
ดังที่แสดงในตัวอย่างก่อนหน้านี้ บล็อกสคริปต์หลายบล็อกที่ส่งผ่านโดยใช้พารามิเตอร์ กระบวนการ จะถูกแมปกับพารามิเตอร์ เริ่มต้น และ สิ้นสุด เพื่อหลีกเลี่ยงการแมปนี้ คุณต้องระบุค่าที่ชัดเจนสำหรับพารามิเตอร์ เริ่มต้น และ สิ้นสุด
1..2 | ForEach-Object -Begin $null -Process { 'one' }, { 'two' }, { 'three' } -End $null
one
two
three
one
two
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 เพื่อให้อินพุตได้รับการประมวลผลเป็นชุดที่ 4 คีย์เวิร์ด $using: ใช้เพื่อส่งตัวแปร $Message ไปยังแต่ละบล็อกสคริปต์คู่ขนาน
ตัวอย่างที่ 12: ดึงข้อมูลรายการบันทึกแบบขนาน
ตัวอย่างนี้ดึงข้อมูลรายการบันทึก 50,000 รายการจากบันทึกระบบ 5 รายการบนเครื่อง Windows ภายในเครื่อง
$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พารามิเตอร์ ขนาน ระบุบล็อกสคริปต์ที่ทำงานแบบขนานสำหรับชื่อบันทึกอินพุตแต่ละรายการ พารามิเตอร์ ThrottleLimit ช่วยให้แน่ใจว่าบล็อกสคริปต์ทั้งห้าทำงานพร้อมกัน
ตัวอย่างที่ 13: วิ่งขนานกันเป็นงาน
ตัวอย่างนี้สร้างงานที่รันบล็อกสคริปต์แบบขนาน ครั้งละสองครั้ง
PS> $job = 1..10 | ForEach-Object -Parallel {
"Output: $_"
Start-Sleep 1
} -ThrottleLimit 2 -AsJob
PS> $job
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
23 Job23 PSTaskJob Running True PowerShell …
PS> $job.ChildJobs
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
24 Job24 PSTaskChildJob Completed True PowerShell …
25 Job25 PSTaskChildJob Completed True PowerShell …
26 Job26 PSTaskChildJob Running True PowerShell …
27 Job27 PSTaskChildJob Running True PowerShell …
28 Job28 PSTaskChildJob NotStarted False PowerShell …
29 Job29 PSTaskChildJob NotStarted False PowerShell …
30 Job30 PSTaskChildJob NotStarted False PowerShell …
31 Job31 PSTaskChildJob NotStarted False PowerShell …
32 Job32 PSTaskChildJob NotStarted False PowerShell …
33 Job33 PSTaskChildJob NotStarted False PowerShell …พารามิเตอร์ ThrottleLimit จะจำกัดจำนวนบล็อกสคริปต์แบบขนานที่ทำงานในแต่ละครั้ง พารามิเตอร์ AsJob ทำให้ ForEach-Object cmdlet เพื่อส่งคืนออบเจ็กต์งานแทนที่จะส่งกระแสข้อมูลเอาต์พุตไปยังคอนโซล ตัวแปร $job รับอ็อบเจ็กต์งานที่รวบรวมข้อมูลเอาต์พุตและตรวจสอบสถานะการทำงาน คุณสมบัติ $job.ChildJobs มีงานลูกที่รันบล็อกสคริปต์แบบขนาน
ตัวอย่างที่ 14: การใช้การอ้างอิงตัวแปรที่ปลอดภัยของเธรด
ตัวอย่างนี้เรียกใช้บล็อกสคริปต์แบบขนานเพื่อรวบรวมอ็อบเจ็กต์กระบวนการที่มีชื่อไม่ซ้ำกัน
$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: การยกเลิกข้อผิดพลาดในการดำเนินการแบบขนาน
ตัวอย่างนี้แสดงให้เห็นถึงข้อผิดพลาดในการสิ้นสุดในบล็อกสคริปต์ที่ทำงานแบบขนานหนึ่งรายการ
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: 5Output: 3 ไม่เคยถูกเขียน เนื่องจาก scriptblock แบบขนานสำหรับการวนซ้ำนั้นถูกยกเลิก
บันทึก
ตัวแปรพารามิเตอร์ทั่วไป PipelineVariable ไม่ รองรับในสถานการณ์ Foreach-Object -Parallel แม้ว่าจะใช้คีย์เวิร์ด $using: ก็ตาม
ตัวอย่างที่ 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' can't be retrieved because it has
| not been set in the local session.scriptblock ที่ซ้อนกันไม่สามารถเข้าถึงตัวแปร $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
- พิมพ์ :
Object[]
- นามแฝง :
Args
- ตำแหน่ง:
ตั้งชื่อ
- ค่าเริ่มต้น:
None
- ที่จำเป็น:
False
- ยอมรับอินพุตไปป์ไลน์:
False
- ยอมรับอักขระตัวแทน:
False
-AsJob
ทำให้การเรียกใช้แบบขนานทำงานเป็นงาน PowerShell ออบเจ็กต์งานเดียวจะถูกส่งกลับแทนเอาต์พุตจากบล็อกสคริปต์ที่รันอยู่ อ็อบเจ็กต์งานประกอบด้วยงานย่อยสำหรับแต่ละบล็อกสคริปต์แบบขนานที่รัน คุณสามารถใช้อ็อบเจ็กต์งานกับ cmdlet ของงาน PowerShell เพื่อดูสถานะการทำงานและดึงข้อมูลได้
พารามิเตอร์นี้ถูกนำมาใช้ใน PowerShell 7.0
- พิมพ์ :
SwitchParameter
- ตำแหน่ง:
ตั้งชื่อ
- ค่าเริ่มต้น:
None
- ที่จำเป็น:
False
- ยอมรับอินพุตไปป์ไลน์:
False
- ยอมรับอักขระตัวแทน:
False
-Begin
ระบุบล็อกสคริปต์ที่ทำงานก่อนที่ cmdlet นี้ประมวลผลออบเจ็กต์อินพุตใดๆ บล็อกสคริปต์นี้ทำงานเพียงครั้งเดียวสำหรับไปป์ไลน์ทั้งหมด สำหรับข้อมูลเพิ่มเติมเกี่ยวกับบล็อก begin โปรดดู about_Functions
- พิมพ์ :
ScriptBlock
- ตำแหน่ง:
ตั้งชื่อ
- ค่าเริ่มต้น:
None
- ที่จำเป็น:
False
- ยอมรับอินพุตไปป์ไลน์:
False
- ยอมรับอักขระตัวแทน:
False
-Confirm
แจ้งให้คุณยืนยันก่อนเรียกใช้ cmdlet
- พิมพ์ :
SwitchParameter
- นามแฝง :
cf
- ตำแหน่ง:
ตั้งชื่อ
- ค่าเริ่มต้น:
False
- ที่จำเป็น:
False
- ยอมรับอินพุตไปป์ไลน์:
False
- ยอมรับอักขระตัวแทน:
False
-End
ระบุบล็อกสคริปต์ที่ทำงานหลังจาก cmdlet นี้ประมวลผลวัตถุอินพุตทั้งหมด บล็อกสคริปต์นี้ทำงานเพียงครั้งเดียวสำหรับไปป์ไลน์ทั้งหมด สำหรับข้อมูลเพิ่มเติมเกี่ยวกับบล็อก end โปรดดู about_Functions
- พิมพ์ :
ScriptBlock
- ตำแหน่ง:
ตั้งชื่อ
- ค่าเริ่มต้น:
None
- ที่จำเป็น:
False
- ยอมรับอินพุตไปป์ไลน์:
False
- ยอมรับอักขระตัวแทน:
False
-InputObject
ระบุวัตถุอินพุต ForEach-Object รันบล็อกสคริปต์หรือคำสั่งการดำเนินการในแต่ละออบเจ็กต์อินพุต ป้อนตัวแปรที่มีวัตถุ หรือพิมพ์คำสั่งหรือนิพจน์ที่ได้รับวัตถุ
เมื่อคุณใช้พารามิเตอร์ InputObject กับ ForEach-Object แทนที่จะให้คำสั่ง piping ส่งผลเป็น ForEach-Object InputObject ค่าจะถือเป็นวัตถุเดียว สิ่งนี้จะเกิดขึ้นจริงแม้ว่าค่าดังกล่าวจะเป็นคอลเลกชันที่เป็นผลลัพธ์ของคำสั่ง เช่น -InputObject (Get-Process) เนื่องจาก InputObject ไม่สามารถส่งคืนคุณสมบัติแต่ละรายการจากอาร์เรย์หรือคอลเลกชันของวัตถุได้ เราขอแนะนำว่าหากคุณใช้ ForEach-Object เพื่อดำเนินการกับคอลเลกชันของวัตถุสำหรับวัตถุเหล่านั้น ที่มีค่าเฉพาะในคุณสมบัติที่กำหนด คุณจะใช้ ForEach-Object ในไปป์ไลน์ ดังที่แสดงในตัวอย่างในหัวข้อนี้
- พิมพ์ :
PSObject
- ตำแหน่ง:
ตั้งชื่อ
- ค่าเริ่มต้น:
None
- ที่จำเป็น:
False
- ยอมรับอินพุตไปป์ไลน์:
True
- ยอมรับอักขระตัวแทน:
False
-MemberName
ระบุชื่อของคุณสมบัติสมาชิกที่จะได้รับหรือวิธีการสมาชิกที่จะโทร สมาชิกจะต้องเป็นสมาชิกอินสแตนซ์ ไม่ใช่สมาชิกแบบคงที่
อนุญาตให้ใช้อักขระตัวแทนได้ แต่จะใช้ได้เฉพาะในกรณีที่สตริงผลลัพธ์แก้ไขเป็นค่าที่ไม่ซ้ำ ตัวอย่างเช่น ถ้าคุณเรียกใช้ Get-Process | ForEach -MemberName *Name รูปแบบไวด์การ์ดตรงกับสมาชิกมากกว่าหนึ่งราย ทำให้คำสั่งล้มเหลว
พารามิเตอร์นี้ถูกนำมาใช้ใน Windows PowerShell 3.0
- พิมพ์ :
String
- ตำแหน่ง:
0
- ค่าเริ่มต้น:
None
- ที่จำเป็น:
True
- ยอมรับอินพุตไปป์ไลน์:
False
- ยอมรับอักขระตัวแทน:
True
-Parallel
ระบุบล็อกสคริปต์ที่จะใช้สำหรับการประมวลผลออบเจ็กต์อินพุตแบบขนาน ป้อนบล็อกสคริปต์ที่อธิบายการดำเนินการ
พารามิเตอร์นี้ถูกนำมาใช้ใน PowerShell 7.0
- พิมพ์ :
ScriptBlock
- ตำแหน่ง:
ตั้งชื่อ
- ค่าเริ่มต้น:
None
- ที่จำเป็น:
True
- ยอมรับอินพุตไปป์ไลน์:
False
- ยอมรับอักขระตัวแทน:
False
-Process
ระบุการดำเนินการที่ดำเนินการกับแต่ละออบเจ็กต์อินพุต บล็อกสคริปต์นี้ถูกเรียกใช้สำหรับทุกอ็อบเจ็กต์ในไปป์ไลน์ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับบล็อก กระบวนการ โปรดดู about_Functions
เมื่อคุณจัดเตรียมบล็อกสคริปต์หลายบล็อกให้กับพารามิเตอร์ กระบวนการ บล็อกสคริปต์แรกจะถูกแมปกับบล็อก เริ่มต้น เสมอ หากมีบล็อกสคริปต์เพียงสองบล็อก บล็อกที่สองจะถูกแมปกับบล็อก กระบวนการ หากมีบล็อกสคริปต์ตั้งแต่สามบล็อกขึ้นไป บล็อกสคริปต์แรกจะถูกแมปกับบล็อก begin เสมอ บล็อกสุดท้ายจะถูกแมปกับบล็อก end และบล็อกกลางจะถูกแมป ไปยังบล็อก กระบวนการ
- พิมพ์ :
สคริปต์บล็อค[]
- ตำแหน่ง:
0
- ค่าเริ่มต้น:
None
- ที่จำเป็น:
True
- ยอมรับอินพุตไปป์ไลน์:
False
- ยอมรับอักขระตัวแทน:
False
-RemainingScripts
ระบุบล็อกสคริปต์ทั้งหมดที่ไม่ได้ใช้โดยพารามิเตอร์ กระบวนการ
พารามิเตอร์นี้ถูกนำมาใช้ใน Windows PowerShell 3.0
- พิมพ์ :
สคริปต์บล็อก[]
- ตำแหน่ง:
ตั้งชื่อ
- ค่าเริ่มต้น:
None
- ที่จำเป็น:
False
- ยอมรับอินพุตไปป์ไลน์:
False
- ยอมรับอักขระตัวแทน:
False
-ThrottleLimit
ระบุจำนวนบล็อกสคริปต์ที่ทำงานแบบขนาน ออบเจ็กต์อินพุตจะถูกบล็อกจนกว่าจำนวนบล็อกสคริปต์ที่รันอยู่จะต่ำกว่า ThrottleLimit ค่าเริ่มต้นคือ 5
พารามิเตอร์ ThrottleLimit จำกัดจำนวนของสคริปต์แบบขนานที่ทำงานในแต่ละอินสแตนซ์ของ ForEach-Object -Parallel ไม่จำกัดจำนวนงานที่สามารถสร้างได้เมื่อใช้พารามิเตอร์ AsJob เนื่องจากตัวงานทำงานพร้อมกัน จึงเป็นไปได้ที่จะสร้างงานคู่ขนานจำนวนหนึ่ง โดยแต่ละงานทำงานจนถึงจำนวนจำกัดของบล็อกสคริปต์ที่เกิดขึ้นพร้อมกัน
พารามิเตอร์นี้ถูกนำมาใช้ใน PowerShell 7.0
- พิมพ์ :
Int32
- ตำแหน่ง:
ตั้งชื่อ
- ค่าเริ่มต้น:
5
- ที่จำเป็น:
False
- ยอมรับอินพุตไปป์ไลน์:
False
- ยอมรับอักขระตัวแทน:
False
-TimeoutSeconds
ระบุจำนวนวินาทีที่จะรอให้อินพุตทั้งหมดประมวลผลแบบขนาน หลังจากหมดเวลาที่กำหนด สคริปต์ที่รันอยู่ทั้งหมดจะหยุดทำงาน และออบเจ็กต์อินพุตที่เหลือที่ต้องประมวลผลจะถูกละเว้น ค่าเริ่มต้น 0 ปิดใช้งานการหมดเวลา และ ForEach-Object -Parallel สามารถทำงานได้อย่างไม่มีกำหนด การพิมพ์ Ctrl+C ที่บรรทัดคำสั่งจะหยุดคำสั่ง ForEach-Object -Parallel ที่ทำงานอยู่ ไม่สามารถใช้พารามิเตอร์นี้ร่วมกับพารามิเตอร์ AsJob
พารามิเตอร์นี้ถูกนำมาใช้ใน PowerShell 7.0
- พิมพ์ :
Int32
- ตำแหน่ง:
ตั้งชื่อ
- ค่าเริ่มต้น:
0
- ที่จำเป็น:
False
- ยอมรับอินพุตไปป์ไลน์:
False
- ยอมรับอักขระตัวแทน:
False
-UseNewRunspace
ทำให้เกิดการเรียกใช้แบบขนานเพื่อสร้างรันสเปซใหม่สำหรับการวนซ้ำทุกครั้ง แทนที่จะนำรันสเปซจากพูลรันสเปซกลับมาใช้ใหม่
พารามิเตอร์นี้ถูกนำมาใช้ใน PowerShell 7.1
- พิมพ์ :
สวิตช์พารามิเตอร์
- ตำแหน่ง:
ตั้งชื่อ
- ค่าเริ่มต้น:
False
- ที่จำเป็น:
False
- ยอมรับอินพุตไปป์ไลน์:
False
- ยอมรับอักขระตัวแทน:
False
-WhatIf
แสดงสิ่งที่จะเกิดขึ้นหาก cmdlet ทำงาน cmdlet ไม่ทำงาน
- พิมพ์ :
SwitchParameter
- นามแฝง :
wi
- ตำแหน่ง:
ตั้งชื่อ
- ค่าเริ่มต้น:
False
- ที่จำเป็น:
False
- ยอมรับอินพุตไปป์ไลน์:
False
- ยอมรับอักขระตัวแทน:
False
อินพุต
PSObject
คุณสามารถไปป์วัตถุใด ๆ ไปที่ cmdlet นี้
เอาท์พุต
PSObject
cmdlet นี้ส่งคืนวัตถุที่กำหนดโดยอินพุต
หมายเหตุ
PowerShell มีนามแฝงต่อไปนี้สำหรับ ForEach-Object:
แพลตฟอร์มทั้งหมด:
%
foreachForEach-Object cmdlet ทำงานเหมือนกับคำสั่ง Foreach มาก ยกเว้นว่าคุณไม่สามารถไพพ์อินพุตไปยังคำสั่ง Foreach ได้ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับคำสั่ง Foreach โปรดดูที่ about_Foreach
เริ่มต้นใน PowerShell 4.0 วิธีการ Where และ ForEach ถูกเพิ่มเพื่อใช้กับคอลเลกชัน คุณสามารถอ่านเพิ่มเติมเกี่ยวกับวิธีการใหม่เหล่านี้ได้ที่นี่ about_arrays
การใช้ ForEach-Object -Parallel:
ForEach-Object -Parallelรันแต่ละบล็อกสคริปต์ในรันสเปซใหม่ รันสเปซใหม่สร้างโอเวอร์เฮดที่มากกว่าการรันForEach-Objectด้วยการประมวลผลตามลำดับอย่างมาก สิ่งสำคัญคือต้องใช้ ขนาน โดยที่ค่าใช้จ่ายในการทำงานแบบขนานมีน้อยเมื่อเทียบกับการทำงานของบล็อกสคริปต์ ตัวอย่างเช่น:- ประมวลผลสคริปต์ที่เข้มข้นบนเครื่องแบบมัลติคอร์
- สคริปต์ที่ใช้เวลารอผลลัพธ์หรือดำเนินการกับไฟล์
การใช้พารามิเตอร์ ขนาน อาจทำให้สคริปต์ทำงานช้ากว่าปกติมาก โดยเฉพาะอย่างยิ่งถ้าสคริปต์คู่ขนานนั้นไม่สำคัญ ทดลองใช้ ขนาน เพื่อดูว่าจะมีประโยชน์ตรงไหน
เมื่อทำงานแบบขนาน วัตถุที่ตกแต่งด้วย ScriptProperties หรือ ScriptMethods ไม่สามารถรับประกันได้ว่าจะทำงานได้อย่างถูกต้อง หากวัตถุเหล่านั้นทำงานใน Runspace อื่นนอกเหนือจากที่สคริปต์แนบมาแต่แรก .
การเรียกใช้ Scriptblock จะพยายามทำงานในรันสเปซ home เสมอ ไม่ว่าจริงๆ แล้วจะถูกเรียกใช้จากที่ใดก็ตาม อย่างไรก็ตาม ForEach-Object -Parallel จะสร้างรันสเปซชั่วคราวที่ถูกลบหลังการใช้งาน ดังนั้นจึงไม่มีรันสเปซให้สคริปต์ดำเนินการอีกต่อไป
ลักษณะการทำงานนี้สามารถทำงานได้ตราบเท่าที่ยังคงมี home runspace อยู่ อย่างไรก็ตาม คุณอาจไม่ได้รับผลลัพธ์ที่ต้องการหากสคริปต์ขึ้นอยู่กับตัวแปรภายนอกที่ปรากฏเฉพาะใน runspace ของผู้เรียกเท่านั้น ไม่ใช่ใน runspace home
ข้อผิดพลาดที่ไม่สิ้นสุดจะถูกเขียนลงในสตรีมข้อผิดพลาด cmdlet ตามที่เกิดขึ้นในการรัน scriptblocks แบบขนาน เนื่องจากลำดับการดำเนินการ scriptblock แบบขนานนั้นไม่ได้กำหนดไว้ ลำดับที่ข้อผิดพลาดปรากฏในสตรีมข้อผิดพลาดจึงเป็นแบบสุ่ม ในทำนองเดียวกัน ข้อความที่เขียนไปยังสตรีมข้อมูลอื่นๆ เช่น คำเตือน รายละเอียด หรือข้อมูล จะถูกเขียนไปยังสตรีมข้อมูลเหล่านั้นตามลำดับที่ไม่แน่นอน
การยุติข้อผิดพลาด เช่น ข้อยกเว้น จะยุติอินสแตนซ์แบบขนานแต่ละรายการของบล็อกสคริปต์ที่เกิดขึ้น ข้อผิดพลาดในการยุติในบล็อกสคริปต์หนึ่งรายการอาจไม่ทำให้เกิดการยุติ cmdlet Foreach-Object บล็อกสคริปต์อื่นๆ ที่ทำงานแบบขนานจะยังคงทำงานต่อไป เว้นแต่จะพบข้อผิดพลาดในการยุติการทำงานด้วย ข้อผิดพลาดในการยุติจะถูกเขียนลงในสตรีมข้อมูลข้อผิดพลาดเป็น ErrorRecord พร้อมด้วย FullyQualifiedErrorId เป็น PSTaskException ข้อผิดพลาดในการยุติสามารถแปลงเป็นข้อผิดพลาดที่ไม่ยุติได้โดยใช้บล็อก try/catch หรือ trap ของ PowerShell
ตัวแปรพารามิเตอร์ทั่วไป PipelineVariable ไม่ รองรับในสถานการณ์คู่ขนาน แม้ว่าจะใช้คีย์เวิร์ด $using: ก็ตาม
มันเป็นสิ่งสำคัญ
ชุดพารามิเตอร์ ForEach-Object -Parallel เรียกใช้บล็อกสคริปต์แบบขนานบนเธรดกระบวนการที่แยกจากกัน คำสำคัญ $using: อนุญาตให้ส่งผ่านการอ้างอิงตัวแปรจากเธรดการเรียกใช้ cmdlet ไปยังแต่ละเธรดบล็อกสคริปต์ที่ทำงานอยู่ เนื่องจากบล็อกสคริปต์ทำงานในเธรดที่แตกต่างกัน ตัวแปรอ็อบเจ็กต์ที่ส่งผ่านโดยการอ้างอิงจึงต้องใช้อย่างปลอดภัย โดยทั่วไปจะปลอดภัยที่จะอ่านจากวัตถุอ้างอิงที่ไม่มีการเปลี่ยนแปลง หากคุณต้องการแก้ไขสถานะของออบเจ็กต์ คุณต้องใช้ออบเจ็กต์ที่ปลอดภัยของเธรด เช่น ประเภท .NET System.Collection.Concurrent (ดูตัวอย่างที่ 14)