tl;dr
Your own solution avoids the original problem, and is arguably the better approach to begin with: Create the .Block3
property as an array via the original JSON (rather than later via Add-Member
), and add elements to that array later with +=
.
However, you could have fixed the original problem by simply (but obscurely) passing
-NotePropertyValue $newblock.psobject.BaseObject
instead of
-NotePropertyValue $newblock
, which removes the invisible [psobject]
wrapper around the array stored in $newblock
that caused the problem. Read on for an explanation.
What matters in the end is: the array stored in the .Block3
property must not have an invisible [psobject]
wrapper, because in Windows PowerShell that causes the array to serialize to JSON wrapped in an extra object with "Count"
and "values"
properties.
The extra object stem from the presence of an obsolete ETS (extended-type system) property named .Count
for arrays, which takes effect for [psobject]
-wrapped arrays - see this answer for the gory details.
The problem no longer surfaces in PowerShell [Core] v6+, because this ETS property has been removed there.
Add-Member was the wrong approach, since it adds a PSObject or PSCustomObject under the covers.
Actually, Add-Member
by itself does not do that, because the -NotePropertyValue
parameter is [object]
-typed, not [psobject]
-typed.
The array stored in your $newblock
variable must already have been [psobject]
wrapped:
$newblock -is [psobject]
probably indicates $true
for you, whereas a regular array does not (e.g., 1, 2 -is [psobject]
is $false
)
For instance, an array returned from a cmdlet, as a whole will have an invisible [psobject]
wrapper, notably when you use the New-Object
cmdlet:
(New-Object string[] 2) -is [psobject]
returns $true
See this GitHub issue for all scenarios in which this invisible extra [psobject]
wrapper is added, which can cause other subtle behavioral differences as well, which still affect PowerShell [Core] as of v7.0 (but, as stated, this particular issue has been fixed by the removal of the ETS property).
There are two general workarounds:
Examples:
Session-wide workaround:
# 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
]
Workaround for a given array variable:
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
]