Powershell Foreach-Object ведет себя ненормально при нулевых значениях [duplicate]

На этот вопрос уже есть ответ здесь:

Всего 1 ответ


Я проследил различия между $items | forEach-Object { Write-host "hello"} $items | forEach-Object { Write-host "hello"} и $null | ForEach-Object { Write-Host "hello"} $null | ForEach-Object { Write-Host "hello"} через Trace-Command .

   PS C:>Trace-Command -Name parameterbinding -Expression {  $items | ForEach-Object { write-host "hello" } } -PSHost
   DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Out-Null]
   DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Out-Null]
   DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Out-Null]
   ....


   PS C:> Trace-Command -Name parameterbinding -Expression {  $null | ForEach-Object { write-host "hello" } } -PSHost
   DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [ForEach-Object]
   DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [ForEach-Object]
   DEBUG: ParameterBinding Information: 0 :     BIND arg [ write-host "hello" ] to parameter [Process]
   DEBUG: ParameterBinding Information: 0 :         Binding collection parameter Process: argument type [ScriptBlock], parameter type [System.Management.Automation.ScriptBlock[]], collection type Array, element type [System.Management.Automation.ScriptBlock], no

Кажется, что $items указывает на командлет Out-Null , который отображается через:

DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Out-Null]

Таким образом, похоже, что Get-ChildItem возвращает ссылку на Out-Null в случае ошибки. Если вы сравните это с $null | ForEach-Object ... $null | ForEach-Object ... вы увидите, что ForEach-Object будет вызываться напрямую:

DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [ForEach-Object]

Что также интересно, если вы используете ForEach-Object с параметром -InputObject код работает в соответствии с запросом:

 PS C:> Trace-Command -Name parameterbinding -Expression {  ForEach-Object -InputObject $items -Process { write-host "hello" } } -PSHost
 DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [ForEach-Object]
 DEBUG: ParameterBinding Information: 0 :     BIND arg [] to parameter [InputObject]

Итак, мое «предположение» заключается в следующем. В случае ошибки ( Get-ChildItem ) вы не увидите, что код ниже выводит вывод:

PS C:> Get-ChildItem -Path "notExisting" | ForEach-Object { Write-Host "found" }

Это имеет смысл, Get-ChildItem «вызывает» Out-Null который очистит конвейер, который разорвет цепочку конвейера (= если ничего не найдено, ничего не должно быть напечатано).

Основываясь на этом, вызывается этот оператор вызова $items = Get-ChildItem -Path "someNotExistingPath" , но Get-ChildItem возвращает нулевой тип, который не равен $null . При выполнении этого кода if($null -EQ $items) PowerShell будет более или менее выполнять неявное приведение типа Get-ChildItem -null-type к $null . Когда дело доходит до этого вызова $items | ForEach-Object $items | ForEach-Object больше ничего не следует отправлять в конвейер, так как $items содержит результат Out-Null .

ОБНОВИТЬ:

В то же время @iRon также добавил дубликат ссылки, которая объясняет Я сохраню ответ, так как эта Trace-Command . Надеюсь, это нормально для сообщества.

Надеюсь, это поможет.


Есть идеи?

10000