I'm trying to understand differences in ConvertTo-Json
behaviour when calling the Cmdlet directly using the -InputObject
parameter, and when passing objects in the pipeline. Please see the below code:
# Convert output to Json, pipe to the Cmdlet
$jsonString = Get-PhysicalDisk | ConvertTo-Json
$disks = $jsonString | ConvertFrom-Json
$disks.Size
# Output: 1024209543168
All OK, seems normal
$jsonString = ConvertTo-Json -InputObject (Get-PhysicalDisk)
$disks = $jsonString | ConvertFrom-Json
$disks.Size
# No output
$null -eq $disks.Size
# True
Why is there a difference when using the InputObject
parameter in this way?
Using PowerShell 5.1, Windows Server 2019
You're seeing a bug, affecting both Windows PowerShell (the legacy, ships-with-Windows, Windows-only edition of PowerShell whose latest and last version is 5.1) and PowerShell (Core) 7 (the modern, cross-platform, install-on-demand edition) as of v7.4.x:
Unless Get-PhysicalDisk
's output objects are [psobject]
-wrapped, ConvertTo-Json
doesn't serialize their ETS (Extended Type System) properties.
As such, this bug is yet another manifestation of the problem discussed in GitHub issue #5579, namely that the presence or absence of the meant-to-be-invisible helper type [psobject]
causes changes in behavior.
The bug at hand affects all CDXML-based cmdlets that do not emit [psobject]
wrapped objects themselves, and has been reported in GitHub issue #24554.
In the pipeline, this [psobject]
-wrapping happens implicitly, whereas it doesn't when you pass the results of a call as an argument.
Get-Date
or Get-ChildItem
, so that their output is [psobject]
-wrapped even when passed by argument.Workaround:
By piping the output to Write-Output
, which simply relays it, [psobject]
wrapping is ensured:
$jsonString = ConvertTo-Json -InputObject (Get-PhysicalDisk | Write-Output)