ค้นหาเว็บไซต์

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: 5

Output: 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:

  • แพลตฟอร์มทั้งหมด:

      %
      foreach

ForEach-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)

บทความที่เกี่ยวข้อง