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


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поддерживает блоки и beginprocess блокиend, как описано в about_Functions.

    Замечание

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

  • Упрощенный синтаксис. Используя упрощенный синтаксис, вы указываете свойство или имя метода объекта в конвейере. ForEach-Object возвращает значение свойства или метода для каждого объекта в конвейере.

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

    Get-Process | ForEach-Object ProcessName

    Упрощенный синтаксис появился в Windows PowerShell 3.0. Дополнительные сведения см. в about_Simplified_Syntax.

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

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

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

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

Примеры

Пример 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 на 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 и сохраняет свойство сообщения каждого события в этом файле. Последний параметр 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, то в создается подключ 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 передается каждому блоку скрипта для сбора объектов. Так как ParallelDictionary является потокобезопасной, он безопасно изменяться каждым параллельным скриптом. Непоточное безопасное объект, например System.Collections.Generic.Dictionary, не будет безопасным для использования здесь.

Замечание

В этом примере используется неэффективный параметр Parallel . Скрипт добавляет входной объект в параллельный объект словаря. Это тривиальный и не стоит затраты на вызов каждого скрипта в отдельном потоке. Выполнение 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 никогда не записывается, так как параллельный блок скрипта для этой итерации был завершен.

Замечание

Общие переменные параметров PipelineVariableне поддерживаются в сценариях даже с ForEach-Object -Parallel модификатором Using: области.

Пример 17. Передача переменных в вложенных параллельных скриптах

Вы можете создать переменную за пределами ForEach-Object -Parallel области скрипта и использовать ее внутри скриптблока с модификатором Using: области. Начиная с PowerShell 7.2, можно создать переменную внутри области скрипта и использовать ее в ForEach-Object -Parallel вложенном блоке скрипта.

$test1 = 'TestA'
1..2 | ForEach-Object -Parallel {
    $Using:test1
    $test2 = 'TestB'
    1..2 | ForEach-Object -Parallel {
        $Using:test2
    }
}

TestA
TestA
TestB
TestB
TestB
TestB

Замечание

В версиях до PowerShell 7.2 вложенный блок скриптов не может получить доступ к переменной $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[]
Aliases:Args
Position:Named
Default value:None
Обязательно:False
Принять входные данные конвейера:False
Принять подстановочные знаки:False

-AsJob

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

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

Тип:SwitchParameter
Position:Named
Default value:None
Обязательно:False
Принять входные данные конвейера:False
Принять подстановочные знаки:False

-Begin

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

Тип:ScriptBlock
Position:Named
Default value:None
Обязательно:False
Принять входные данные конвейера:False
Принять подстановочные знаки:False

-Confirm

Запрашивает подтверждение перед запуском cmdlet.

Тип:SwitchParameter
Aliases:cf
Position:Named
Default value:False
Обязательно:False
Принять входные данные конвейера:False
Принять подстановочные знаки:False

-End

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

Тип:ScriptBlock
Position:Named
Default value:None
Обязательно:False
Принять входные данные конвейера:False
Принять подстановочные знаки:False

-InputObject

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

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

Тип:PSObject
Position:Named
Default value:None
Обязательно:False
Принять входные данные конвейера:True
Принять подстановочные знаки:False

-MemberName

Указывает имя свойства члена, которое нужно получить или вызвать метод-член. Элементы должны быть элементами экземпляра, а не статическими.

Подстановочные знаки разрешены, но работают только в том случае, если результирующая строка разрешает уникальное значение. Например, при запуске Get-Process | foreach -MemberName *Nameшаблон подстановочного знака соответствует нескольким членам, что приводит к сбою команды.

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

Тип:String
Position:0
Default value:None
Обязательно:True
Принять входные данные конвейера:False
Принять подстановочные знаки:True

-Parallel

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

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

Тип:ScriptBlock
Position:Named
Default value:None
Обязательно:True
Принять входные данные конвейера:False
Принять подстановочные знаки:False

-Process

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

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

Тип:ScriptBlock[]
Position:0
Default value:None
Обязательно:True
Принять входные данные конвейера:False
Принять подстановочные знаки:False

-RemainingScripts

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

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

Тип:ScriptBlock[]
Position:Named
Default value:None
Обязательно:False
Принять входные данные конвейера:False
Принять подстановочные знаки:False

-ThrottleLimit

Указывает количество блоков скриптов, выполняемых параллельно. Входные объекты блокируются до тех пор, пока число блоков запуска скрипта не будет ниже ThrottleLimit. Значение по умолчанию — 5.

Параметр ThrottleLimit ограничивает количество параллельных скриптов, выполняемых во время каждого экземпляра ForEach-Object -Parallel. Это не ограничивает количество заданий, которые можно создать при использовании параметра AsJob . Так как задания выполняются одновременно, можно создать ряд параллельных заданий, каждое из которых выполняется до ограничения числа одновременных блокировок скриптов.

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

Тип:Int32
Position:Named
Default value:5
Обязательно:False
Принять входные данные конвейера:False
Принять подстановочные знаки:False

-TimeoutSeconds

Указывает количество секунд, ожидающее параллельной обработки всех входных данных. После указанного времени ожидания все выполняемые скрипты будут остановлены. И все остальные входные объекты, которые будут обработаны, игнорируются. Значение 0 по умолчанию отключает время ожидания и ForEach-Object -Parallel может выполняться на неопределенный срок. Ввод клавиш CTRL+C в командной строке останавливает выполнение ForEach-Object -Parallel команды. Этот параметр нельзя использовать вместе с параметром AsJob .

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

Тип:Int32
Position:Named
Default value:0
Обязательно:False
Принять входные данные конвейера:False
Принять подстановочные знаки:False

-UseNewRunspace

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

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

Тип:SwitchParameter
Position:Named
Default value:False
Обязательно:False
Принять входные данные конвейера:False
Принять подстановочные знаки:False

-WhatIf

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

Тип:SwitchParameter
Aliases:wi
Position:Named
Default value:False
Обязательно:False
Принять входные данные конвейера:False
Принять подстановочные знаки:False

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

PSObject

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

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

PSObject

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

Примечания

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

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

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

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

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

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

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

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

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

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

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

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

    Завершающие ошибки, такие как исключения, завершают отдельный параллельный экземпляр скриптов, в котором они происходят. Завершающая ошибка в одном блоке скриптов может не вызвать завершение командлета ForEach-Object . Другие блоки скриптов, выполняемые параллельно, продолжают выполняться, если они также не сталкиваются с завершающейся ошибкой. Завершающая ошибка записывается в поток данных об ошибках в виде errorRecord с полнофункциональнымErrorIdPSTaskException. Завершающие ошибки можно преобразовать в неисключающие ошибки с помощью PowerShell try/catch или trap блоков.

  • Общие переменные параметров PipelineVariableне поддерживаются в параллельных сценариях даже с модификатором Using: области.

    Это важно

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