tl;dr
最后重要的是:存储在.Block3属性中的数组不能有不可见的[psobject]包装器,因为在 Windows PowerShell 中会导致数组序列化为 JSON,该 JSON 包装在具有 "Count" 和 "values" 属性的额外对象中。
额外的对象源于存在名为 .Count 的用于数组的过时 ETS(扩展类型系统)属性,该属性对 [psobject] 包装的数组生效 - 有关血腥细节,请参阅 this answer。
PowerShell [Core] v6+ 中不再出现此问题,因为该 ETS 属性已在此处删除。
Add-Member 是错误的方法,因为它在幕后添加了 PSObject 或 PSCustomObject。
实际上,Add-Member 本身不会这样做,因为-NotePropertyValue 参数是[object]-typed,而不是[psobject]-typed。
存储在您的$newblock 变量中的数组必须已经被[psobject] 包装:
$newblock -is [psobject] 可能为您指示$true,而常规数组则没有(例如,1, 2 -is [psobject] 是@987654346 @)
例如,从 cmdlet 返回的数组作为一个整体将有一个不可见的 [psobject] 包装器,尤其是当您使用 New-Object cmdlet 时:(New-Object string[] 2) -is [psobject] 返回$true
请参阅 this GitHub issue,了解添加了这个不可见的额外 [psobject] 包装器的所有场景,这也可能导致其他细微的行为差异,从 v7.0 起仍会影响 PowerShell [Core](但是,如前所述, 此特定问题已通过删除 ETS 属性得到解决)。
有两种一般解决方法:
-
会话范围:
- 在调用
ConvertTo-Json 之前,运行以下命令,删除过时的 ETS 属性,之后数组按预期序列化 - 无论 [psobject]-wrapped 与否:
Remove-TypeData System.Array
-
对于给定的数组变量:
- 使用
.psobject.BaseObject 访问数组的未包装底层.NET 数组;在你的情况下:$newblock.psobject.BaseObject
示例:
会话范围的解决方法:
# The problem: Serialize a [psobject]-wrapped array (0, 0):
PS> ConvertTo-Json -InputObject (New-Object int[] 2)
# Note the extra object with the "count" (element count) and "value" property (elements)
{
"value": [
0,
0
],
"Count": 2
}
# Remove the ETS definitions for System.Array
Remove-TypeData System.Array
# Rerun the command:
PS> ConvertTo-Json -InputObject (New-Object int[] 2)
# OK
[
0,
0
]
给定数组变量的解决方法:
PS> $arr = New-Object int[] 2; ConvertTo-Json -InputObject $arr
# Note the extra object with the "count" (element count) and "value" property (elements)
{
"value": [
0,
0
],
"Count": 2
}
# $arr.psobject.BaseObject bypasses the [psobject] wrapper
PS> ConvertTo-Json -InputObject $arr.psobject.BaseObject
# OK
[
0,
0
]