PowerShell -is оператор всегда соответствует PSCustomObject при использовании в ForEach-Object

Использование PowerShell Core 6.1 на Mac. Похоже, что конвейерная передача массива в ForEach-Object изменяет или обертывает каждый элемент таким образом, что оператор -is считает, что все они являются PSCustomObjects.

Позвольте мне продемонстрировать:

Настройте массив из четырех элементов разных типов (использование JSON, потому что в моем реальном варианте использования данные поступают именно отсюда):

$a = '[4, "Hi", {}, true]' | ConvertFrom-Json

Итерируйте список по индексу и определите, какие из них являются PSCustomObjects:

0..3 | ForEach-Object { 
    $v = $a[$_]
    $t = $v.GetType().FullName
    $is = $v -is [PSCustomObject]
    "$t - $is"
}

Результат (для меня) именно то, что я ожидал:

System.Int64 - False
System.String - False
System.Management.Automation.PSCustomObject - True
System.Boolean - False

Но если я просто передаю массив ForEach-Object:

$a | ForEach-Object { 
    $v = $_
    $t = $v.GetType().FullName
    $is = $v -is [PSCustomObject]
    "$t - $is"
}

Теперь в выходных данных утверждается, что все четыре являются объектами PSCustomObject:

System.Int64 - True
System.String - True
System.Management.Automation.PSCustomObject - True
System.Boolean - True

Может ли кто-нибудь объяснить, что здесь происходит?


person user221592    schedule 12.11.2018    source источник
comment
[PSCustomObject] - это псевдоним для [System.Management.Automation.PSObject], но не для [System.Management.Automation.PSCustomObject]. Это означает, что все четыре заключены в [PSObject] внутри ForEach-Object командлета. Вероятно, потому что параметр InputObject для ForEach-Object, набранный как [PSObject] и ForEach-Object, не выполняет разворачивание.   -  person user4003407    schedule 12.11.2018


Ответы (1)


PetSerAl, как он часто это делает, предоставил важный указатель в комментарии:

Подключение объектов к ForEach-Object обертывает их в [psobject] экземпляр (как отражено в $_ / $PSItem), что заставляет -is [pscustomobject] / -is [psobject] возвращать $True для любого входного объекта, потому что - что сбивает с толку - [pscustomobject] то же самое, что [psobject]: они оба являются ускорителями типов для [System.Management.Automation.PSObject] - вопреки тому, что можно было бы ожидать, [pscustomobject] не сокращение от [System.Management.Automation.PSCustomObject].

Поэтому проверьте, что входные объекты являются экземплярами [System.Management.Automation.PSCustomObject], а не [pscustomobject]:

$a | ForEach-Object {
  $_ -is [System.Management.Automation.PSCustomObject]
}

Обратите внимание, что если вы используете foreach цикл, даже -is [pscustomobject] будет работать, потому что в этом случае перечисляемые объекты не заключены в дополнительный [psobject] экземпляр:

foreach ($element in $a) {
  $element -is [pscustomobject]
}

Это работает, потому что даже добросовестный [System.Management.Automation.PSCustomObject] технически также [System.Management.Automation.PSObject] за кулисами.

person mklement0    schedule 13.11.2018