-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Description
Instances of types that normally serialize to a JSON scalar (basic JSON data type: string, number, Boolean) should not serialize to objects just because - situationally - NoteProperty and ScriptProperty members may be present - not least because such members may be added automatically by PowerShell.
Additionally, the current behavior is inconsistent, possibly related to #5579.
Also, with a ScriptProperty member present on a [string] instance, ConvertTo-Json crashes as of PowerShell Core v6.1.0-preview.3 - see #7091
Steps to reproduce
[ordered] @{ d1 = [datetime]::now; d2 = get-date } | ConvertTo-JsonExpected behavior
{
"d1": "2018-01-05T09:25:37.037783+01:00",
"d2": "2018-01-05T09:25:37.037783+01:00",
}
Actual behavior
{
"d1": "2018-01-05T09:25:37.037783+01:00",
"d2": {
"value": "2018-01-05T09:25:37.037915+01:00",
"DisplayHint": 2,
"DateTime": "Friday, January 5, 2018 9:25:37 AM"
}
}
Note how the presence of the DisplayHint and DateTime members added by Get-Date caused the value to no longer serialize as a single string, but as an object with said members (yet not any of the type's regular properties).
In some cases, using an intermediate variable makes the problem go away:
$dt = get-date
[ordered] @{ d1 = [datetime]::now; d2 = $dt } | ConvertTo-Json # OKThat said, with other objects, such as those with provider-added properties, the problem surfaces even with an intermediate variable:
'hi' > t.txt
$s = Get-Content t.txt
$s | ConvertTo-Json # !! outputs a JSON object with many provider propertiesAgain, what normally serializes as a string is unexpectedly serialized as an object due to the presence of NoteProperty members.
Finally, when sending an instance with even just a ScriptProperty member through the pipeline, the problem surfaces too:
> [datetime]::now | ConvertTo-Json
{
"value": "2018-01-07T06:18:29.821274+01:00",
"DateTime": "Sunday, January 7, 2018 6:18:29 AM"
}Note that if the instance is nested inside a hashtable / custom object, the problem does not occur, as demonstrated above.
It also doesn't occur if you use -InputObject instead of the pipeline: ConvertTo-Json ([datetime]::now)
Workarounds
Either: apply .psobject.baseobject to the command producing the object to serialize to JSON:
@{ d = (Get-Date).psobject.BaseObject } | ConvertTo-JsonOr: cast to the expected type (or, with an intermediate variable, type-constrain it):
@{ d = [datetime] (Get-Date) } | ConvertTo-JsonNote: The above workarounds only work if the problematic object is not the input object as a whole.
If so, the only workaround I'm aware of is to pass the input object via -InputObject rather than the pipeline:
ConvertTo-Json ([datetime] (Get-Date)) # OK, due to using -InputObject
# !! BROKEN, due to using the pipeline, though, curiously, only
# !! the "DateTime" ScriptProperty shows up, not the "DisplayHint" NoteProperty
[datetime] (Get-Date) | ConvertTo-Json Environment data
PowerShell Core v6.0.0-rc.2 (v6.0.0-rc.2) on macOS 10.13.2