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


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и end processблоки, как описано в about_functions.

    Примечание.

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

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

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

    Get-Process | ForEach-Object ProcessName

  • Параллельный блок скриптов параллельного выполнения. Начиная с 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. Получение длины всех файлов в каталоге

В этом примере файлы и каталоги обрабатываются в каталоге $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 и хранения свойства сообщения каждого из событий в этом файле. Последний параметр End используется для отображения даты и времени после завершения обработки.

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

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

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

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

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

Команда использует 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-Object foreach для командлета и исключает имена параметров 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. Передача переменных в вложенный параллельный скрипт ScriptBlockSet

Вы можете создать переменную за пределами Foreach-Object -Parallel области скрипта и использовать ее внутри скриптблока с ключевым словом $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.

Вложенный блок скриптов не может получить доступ к переменной $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

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

Тип: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

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

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

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