PowerShell -is 运算符在 ForEach-Object 中使用时始终匹配 PSCustomObject

PowerShell -is operator always matching PSCustomObject when used in ForEach-Object

在 Mac 上使用 PowerShell Core 6.1。似乎将数组通过管道传递给 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"
}

现在输出声称所有四个都是 PSCustomObjects:

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

谁能解释一下这里发生了什么?

PetSerAl,正如他经常做的那样,在评论中提供了关键指针:

将对象通过管道传送到 ForEach-Object 会将它们包装在 [psobject] 实例中(如 $_ / $PSItem 中所反映),这会导致 -is [pscustomobject] / -is [psobject] 到 return $True 对于 any 输入对象 ,因为 - 令人困惑 - [pscustomobject] 是与 [psobject] 相同:它们都是 [System.Management.Automation.PSObject] 的类型加速器 - 与人们的预期相反,[pscustomobject] 而不是 [=23= 的缩写].

因此,测试输入对象是否是 [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]