Поделиться через


ForEach-Object

Выполняет операцию для каждого элемента в коллекции входных объектов.

Синтаксис

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>]

Описание

Командлет ForEach-Object выполняет операцию с каждым элементом в коллекции входных объектов. Входные объекты можно передать в командлет или указать с помощью параметра InputObject .

Начиная с Windows PowerShell 3.0 существует два разных способа создания ForEach-Object команды.

  • Блок скрипта. Можно использовать блок скрипта, чтобы указать операцию. В блоке скрипта $_ используйте переменную для представления текущего объекта . Блок скрипта — это значение параметра Process. Блок скрипта может содержать любой скрипт PowerShell.

    Например, следующая команда возвращает значение свойства ProcessName каждого процесса на компьютере.

    Get-Process | ForEach-Object {$_.ProcessName}

    ForEach-Object поддерживает блоки begin, processи end , как описано в about_functions.

    Примечание

    Блоки скриптов выполняются в область вызывающей стороны. Таким образом, блоки имеют доступ к переменным в этом область и могут создавать новые переменные, которые сохраняются в этом область после завершения командлета.

  • Оператор Operation. Можно также написать оператор операции, который больше похож на естественный язык. С помощью инструкции операции можно указать значение свойства или вызвать метод. Инструкции операций появились в Windows PowerShell 3.0.

    Например, следующая команда также возвращает значение свойства ProcessName каждого процесса на компьютере.

    Get-Process | ForEach-Object ProcessName

  • Параллельно выполняющаяся блокировка скрипта. Начиная с PowerShell 7.0 доступен третий набор параметров, который запускает каждый блок скрипта параллельно. Параметр ThrottleLimit ограничивает количество параллельных скриптов, выполняемых одновременно. Как и ранее, используйте $_ переменную для представления текущего входного объекта в блоке скрипта. $using: Используйте ключевое слово для передачи ссылок на переменные в выполняющуюся скрипт.

    В PowerShell 7 для каждой итерации цикла создается новое пространство выполнения, чтобы обеспечить максимальную изоляцию. Это может быть большое снижение производительности и ресурсов, если выполняемая работа невелика по сравнению с созданием новых пространств выполнения или если существует много итераций, выполняющих значительную работу. Начиная с PowerShell 7.1, пространства выполнения из пула runspace повторно используются по умолчанию. Параметр ThrottleLimit задает размер пула пространства выполнения. Размер пула пространств выполнения по умолчанию — 5. Вы по-прежнему можете создать новое пространство выполнения для каждой итерации с помощью параметра UseNewRunspace .

    По умолчанию параллельные блоки скриптов используют текущий рабочий каталог вызывающей стороны, которая запустила параллельные задачи.

    Дополнительные сведения см. в разделе NOTES этой статьи.

Примеры

Пример 1. Деление целых чисел в массиве

В этом примере принимается массив из трех целых чисел и каждое из них делится на 1024.

30000, 56798, 12432 | ForEach-Object -Process {$_/1024}

29.296875
55.466796875
12.140625

Пример 2. Получение длины всех файлов в каталоге

В этом примере обрабатываются файлы и каталоги в каталоге $PSHOMEустановки PowerShell .

Get-ChildItem $PSHOME |
  ForEach-Object -Process {if (!$_.PSIsContainer) {$_.Name; $_.Length / 1024; " " }}

Если объект не является каталогом, блок скрипта получает имя файла, делит значение его свойства Length на 1024 и добавляет пробел (" "), чтобы отделить его от следующей записи. Командлет использует свойство PSISContainer , чтобы определить, является ли объект каталогом.

Пример 3. Работа с последними событиями системы

В этом примере записывается 1000 последних событий из журнала системных событий в текстовый файл. Текущее время отображается до и после обработки событий.

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 получает 1000 последних событий из журнала системных событий и передает их в ForEach-Object командлет . Параметр Begin используется для отображения текущей даты и времени. Затем параметр Process использует Out-File командлет для создания текстового файла с именем events.txt и сохраняет свойство message каждого события в этом файле. Наконец, параметр End используется для отображения даты и времени после завершения обработки.

Пример 4. Изменение значения раздела реестра

В этом примере значение записи реестра RemotePath во всех подразделах раздела HKCU:\Network изменяется на текст в верхнем регистре.

Get-ItemProperty -Path HKCU:\Network\* |
  ForEach-Object {
    Set-ItemProperty -Path $_.PSPath -Name RemotePath -Value $_.RemotePath.ToUpper()
  }

Этот формат можно использовать для изменения формы или содержимого раздела реестра.

Каждый подраздел в разделе Network представляет сопоставленный сетевой диск, который повторно подключается при входе. Запись RemotePath содержит UNC-путь подключенного диска. Например, если сопоставить E: диск с \\Server\Share, в HKCU:\Network создается подраздел E со значением реестра RemotePath, равным \\Server\Share.

Команда использует Get-ItemProperty командлет для получения всех подразделов сетевого ключа, а Set-ItemProperty командлет — для изменения значения записи реестра RemotePath в каждом разделе. В команде Set-ItemProperty путь является значением свойства PSPath раздела реестра. Это свойство объекта Microsoft платформа .NET Framework, представляющее раздел реестра, а не запись реестра. Команда использует метод ToUpper() значения RemotePath , который является строковым REG_SZ.

Так как Set-ItemProperty изменяет свойство каждого ключа, для доступа к свойству ForEach-Object требуется командлет .

Пример 5. Использование автоматической переменной $null

В этом примере показан эффект отправки автоматической переменной $null в ForEach-Object командлет .

1, 2, $null, 4 | ForEach-Object {"Hello"}

Hello
Hello
Hello
Hello

Так как PowerShell обрабатывается $null как явный заполнитель, ForEach-Object командлет создает значение для $null , как и для других объектов, которые передаются в него.

Пример 6. Получение значений свойств

В этом примере возвращается значение свойства Path всех установленных модулей PowerShell с помощью параметра MemberName командлета ForEach-Object .

Get-Module -ListAvailable | ForEach-Object -MemberName Path
Get-Module -ListAvailable | Foreach Path

Вторая команда эквивалента первой. Он использует Foreach псевдоним командлета ForEach-Object и пропускает имя параметра MemberName , который является необязательным.

Командлет ForEach-Object полезен для получения значений свойств, так как он получает значение без изменения типа, в отличие от командлетов Format или Select-Object командлетов, которые изменяют тип значения свойства.

Пример 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 и пропускает имена параметров MemberName и ArgumentList , которые являются необязательными.

Пример 8. Использование ForEach-Object с двумя блоками скриптов

В этом примере мы передаем два блока скрипта позиционально. Все блоки скриптов привязываются к параметру Process . Однако они обрабатываются так, как если бы они были переданы в параметры Begin и Process .

1..2 | ForEach-Object { 'begin' } { 'process' }

begin
process
process

Пример 9. Использование ForEach-Object с более чем двумя блоками скриптов

В этом примере мы передаем четыре блока скрипта позиционально. Все блоки скриптов привязываются к параметру Process . Однако они обрабатываются так, как если бы они были переданы в параметры Begin, Process и End .

1..2 | ForEach-Object { 'begin' } { 'process A' }  { 'process B' } { 'end' }

begin
process A
process B
process A
process B
end

Примечание

Первый блок скрипта всегда сопоставляется с блоком begin , последний блок сопоставляется с блоком end , а два средних блока сопоставляются с блоком process .

Пример 10. Запуск нескольких блоков скрипта для каждого элемента конвейера

Как показано в предыдущем примере, несколько блоков скриптов, переданных с помощью параметра Process , сопоставляются с параметрами Begin и End . Чтобы избежать этого сопоставления, необходимо указать явные значения для параметров Begin и End .

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, чтобы входные данные обрабатывались пакетами по четыре. Ключевое слово $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

Параметр Parallel указывает блок скрипта, который выполняется параллельно для каждого имени входного журнала. Параметр 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 командлет возвращает объект задания вместо потоковой передачи выходных данных в консоль. Переменная $job получает объект задания, который собирает выходные данные и отслеживает состояние выполнения. Свойство $job.ChildJobs содержит дочерние задания, которые выполняют параллельные блоки скриптов.

Пример 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, не будет безопасным для использования здесь.

Примечание

Этот пример является неэффективным использованием параметра Parallel . Скрипт добавляет входной объект в параллельный объект словаря. Это тривиальная и не стоит накладных расходов, связанных с вызовом каждого скрипта в отдельном потоке. Работа ForEach-Object без коммутатора Parallel является более эффективной и быстрой. Этот пример предназначен только для демонстрации того, как использовать потокобезопасные переменные.

Пример 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 никогда не записывается, так как параллельный 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.

Type:Object[]
Aliases:Args
Position:Named
Default value:None
Required:False
Accept pipeline input:False
Accept wildcard characters:False

-AsJob

Приводит к запуску параллельного вызова как задания PowerShell. Возвращается один объект задания вместо выходных данных из выполняющихся блоков скриптов. Объект job содержит дочерние задания для каждого параллельного блока скрипта, который выполняется. Объект задания можно использовать с любым из командлетов задания PowerShell, чтобы просмотреть состояние выполнения и получить данные.

Этот параметр появился в PowerShell 7.0.

Type:SwitchParameter
Position:Named
Default value:None
Required:False
Accept pipeline input:False
Accept wildcard characters:False

-Begin

Задает блок скрипта, который запускается перед обработкой всех входных объектов. Этот блок скрипта выполняется только один раз для всего конвейера. Дополнительные сведения о блоке см. в beginразделе about_Functions.

Type:ScriptBlock
Position:Named
Default value:None
Required:False
Accept pipeline input:False
Accept wildcard characters:False

-Confirm

Запрос подтверждения перед выполнением командлета.

Type:SwitchParameter
Aliases:cf
Position:Named
Default value:False
Required:False
Accept pipeline input:False
Accept wildcard characters:False

-End

Задает блок скрипта, который запускается после того, как этот командлет обрабатывает все входные объекты. Этот блок скрипта выполняется только один раз для всего конвейера. Дополнительные сведения о блоке см. в endразделе about_Functions.

Type:ScriptBlock
Position:Named
Default value:None
Required:False
Accept pipeline input:False
Accept wildcard characters:False

-InputObject

Задает входные объекты. ForEach-Object выполняет блок скрипта или инструкцию операции для каждого входного объекта. Введите переменную, которая содержит объекты, или команду или выражение, которое возвращает объекты.

При использовании параметра InputObject с ForEach-Objectвместо отправки результатов ForEach-Objectкоманды в значение InputObject обрабатывается как один объект. Это верно, даже если значением является коллекция, которая является результатом команды, например -InputObject (Get-Process). Так как InputObject не может возвращать отдельные свойства из массива или коллекции объектов, рекомендуется использовать в конвейере, как показано в примерах в этом разделе, если вы используете ForEach-Object для выполнения операций с коллекцией объектов с ForEach-Object определенными значениями в определенных свойствах.

Type:PSObject
Position:Named
Default value:None
Required:False
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
Required:True
Accept pipeline input:False
Accept wildcard characters:True

-Parallel

Указывает блок скрипта, используемый для параллельной обработки входных объектов. Введите блок скрипта, который описывает операцию.

Этот параметр появился в PowerShell 7.0.

Type:ScriptBlock
Position:Named
Default value:None
Required:True
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
Required:True
Accept pipeline input:False
Accept wildcard characters:False

-RemainingScripts

Указывает все блоки скрипта, которые не принимаются параметром Process .

Этот параметр впервые появился в Windows PowerShell 3.0.

Type:ScriptBlock[]
Position:Named
Default value:None
Required:False
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
Required:False
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
Required:False
Accept pipeline input:False
Accept wildcard characters:False

-UseNewRunspace

Вызывает параллельный вызов для создания нового пространства выполнения для каждой итерации цикла вместо повторного использования пространств выполнения из пула.

Этот параметр появился в PowerShell 7.1

Type:SwitchParameter
Position:Named
Default value:False
Required:False
Accept pipeline input:False
Accept wildcard characters:False

-WhatIf

Показывает, что произойдет при запуске командлета. Командлет не выполняется.

Type:SwitchParameter
Aliases:wi
Position:Named
Default value:False
Required:False
Accept pipeline input:False
Accept wildcard characters:False

Входные данные

PSObject

В этот командлет можно передать любой объект.

Выходные данные

PSObject

Этот командлет возвращает объекты, определенные входными данными.

Примечания

PowerShell включает следующие псевдонимы для ForEach-Object:

  • Все платформы:
    • %
    • foreach

Командлет ForEach-Object работает так же, как оператор Foreach , за исключением того, что вы не можете передать входные данные в оператор Foreach . Дополнительные сведения об операторе Foreach см. в разделе about_Foreach.

Начиная с PowerShell 4.0, WhereForEach и методы были добавлены для использования с коллекциями. Дополнительные сведения об этих новых методах см. здесь about_arrays

Использование среды ForEach-Object -Parallel:

  • ForEach-Object -Parallel выполняет каждый блок скрипта в новом пространстве выполнения. Новые пространства выполнения создают значительно больше накладных расходов, чем выполнение ForEach-Object с последовательной обработкой. Важно использовать функцию Parallel , когда накладные расходы на параллельное выполнение невелики по сравнению с работой, выполняемой блоком скриптов. Пример:

    • Скрипты для ресурсоемких вычислений на многоядерных компьютерах
    • Скрипты, которые тратят время на ожидание результатов или выполнение операций с файлами

    Использование параметра Parallel может привести к тому, что скрипты выполняются гораздо медленнее, чем обычно. Особенно если параллельные скрипты являются тривиальными. Поэкспериментируйте с Parallel , чтобы узнать, где это может быть полезно.

  • При параллельном выполнении объекты, украшенные свойствами ScriptProperties или ScriptMethods , не могут быть гарантированы для правильной работы, если они выполняются в другом пространстве выполнения, отличном от изначально присоединенных к ним скриптов.

    Вызов scriptblock всегда пытается выполнить в своем домашнем пространстве выполнения, независимо от того, где он фактически вызывается. Однако создаются временные пространства выполнения, ForEach-Object -Parallel которые удаляются после использования, поэтому для выполнения скриптов больше нет пространства выполнения.

    Такое поведение может работать до тех пор, пока домашнее пространство выполнения по-прежнему существует. Однако вы можете не получить нужный результат, если скрипт зависит от внешних переменных, которые присутствуют только в пространстве выполнения вызывающего элемента, а не в домашнем пространстве выполнения.

  • Неустранимые ошибки записываются в поток ошибок командлета по мере их возникновения в параллельно выполняющихся скриптблоках. Так как параллельный порядок выполнения scriptblock не детерминирован, порядок, в котором ошибки появляются в потоке ошибок, является случайным. Аналогичным образом сообщения, записываемые в другие потоки данных, такие как предупреждения, подробные сведения или сведения, записываются в эти потоки данных в неопределенном порядке.

    Завершающие ошибки, такие как исключения, завершают работу отдельного параллельного экземпляра scriptblocks, в котором они происходят. Неустранимая ошибка в одном блоке scriptblock может не привести к завершению командлета Foreach-Object . Другие блоки скриптов, работающие параллельно, продолжают выполняться, если они также не столкнутся с неустранимой ошибкой. Завершающая ошибка записывается в поток данных об ошибке как ErrorRecord с значением FullyQualifiedErrorId .PSTaskException Неустранимые ошибки можно преобразовать в неустранимые с помощью PowerShell try/catch или trap блоков.

  • Переменные общих параметров PipelineVariableне поддерживаются в параллельных сценариях даже при $using: использовании ключевое слово.

    Важно!

    Набор ForEach-Object -Parallel параметров параллельно выполняет блоки скриптов в отдельных потоках процесса. Ключевое слово $using: позволяет передавать ссылки на переменные из потока вызова командлета в каждый выполняемый поток блока скрипта. Так как блоки скрипта выполняются в разных потоках, переменные объекта, передаваемые по ссылке, должны использоваться безопасно. Как правило, это безопасно для чтения из объектов, на которые ссылается ссылка, которые не изменяются. Если необходимо изменить состояние объекта, необходимо использовать потокобезопасные объекты, такие как типы .NET System.Collection.Concurrent (см. пример 14).