PowerShell cmdlet is changing the type of the returned object

171 views Asked by At

This behavior is mystifying!

Consider the following PowerShell script:

[Reflection.Assembly]::LoadFrom("Newtonsoft.Json.dll") | Out-Null

function ConvertFrom-JsonNet {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string] $Json
    )

    $O = [Newtonsoft.Json.Linq.JObject]::Parse($Json)
    Write-Host $O.GetType().Name

    return $O
}

Clear-Host

$Json = '{"test":"prop"}'
$O1 = ConvertFrom-JsonNet '{"test":"prop"}'
$O2 = [Newtonsoft.Json.Linq.JObject]::Parse($Json)

Write-Host $O1.GetType().Name
Write-Host $O2.GetType().Name

You'd expect the output to be:

JObject
JObject
JObject

but it's not! It's:

JObject
JProperty
JObject

How is this possible? How is the type of the object within the function JObject, but then after it's passed out of the function, it's JProperty?

1

There are 1 answers

0
NathanAldenSr On

Sigh

Yay for PowerShell's inflexibility!

Apparently, PowerShell will "unroll" all collections that are destined for the pipeline. In this case, JObject implements ICollection<KeyValuePair<string, JToken>>. The JObject's collection contains a single JProperty, which is what was being "unrolled" into the pipeline. I found this answer, which shows that rolling a collection into an outer collection will cause the intended value to be placed in the pipeline.

Wouldn't it be nice if PowerShell had a mechanism for adding something to the pipeline untouched? :)