locked
How to Output Entire Content of JSON Nested Hash Table in PoweShell RRS feed

  • Question

  • How can I output the entire contents of a nested JSON hash table to a PS object in one line?

    $json = @"
    {
        "outer": "value1",
        "outerArray": [
            "value2",
            "value3"
        ],
        "outerHash": {
            "inner": "value4",
            "innerArray": [
                "value5",
                "value6"
            ],
            "innerHash": {
                "innermost1": "value7",
                "innermost2": "value8",
                "innermost3": "value9"
            }
        }
    }
    "@

    Current behavior: PowerShell by default only displays one level down into the data (you can see here that "innerArray" and "innerHash" are both truncated since they are not in the first level of the data structure

    $json | ConvertFrom-Json
    outer  outerArray       outerHash                                              
    -----  ----------       ---------                                              
    value1 {value2, value3} @{inner=value4; innerArray=System.Object[]; innerHash=}


    Desired behavior: Recursively expand and display all hash/array content (notice that "innerArray" and "innerHash" are both expanded)

    $json | ConvertFrom-Json
    outer  outerArray       outerHash                                              
    -----  ----------       ---------                                              
    value1 {value2, value3} @{inner=value4; innerArray=@(value5, value6); innerHash=@{innermost1=value7; innermost2=value8; innermost3=value9}}

    I understand this entails some sort of custom parsing / formatting but not sure how the code should look. Sample code appreciated.


    • Edited by atscripter Wednesday, February 6, 2019 5:54 PM clarify question
    Wednesday, February 6, 2019 4:25 PM

Answers

  • The solution to this was graciously provided by iRon on another forum. This entailed using the custom ConvertTo-Expression function to iterate through the JSON block and output a PS custom object for each nested hash/array.

    Command:

    $Properties = @{}
    ($Json | ConvertFrom-Json).PSObject.Properties |
        ForEach-Object {$Properties.($_.Name) = $_.Value |
            ConvertTo-Expression -Expand -1}
    [PSCustomObject]$Properties

    Output:

    outer    outerArray        outerHash                                                                                                                                                          
    -----    ----------        ---------                                                                                                                                                          
    'value1' 'value2','value3' [PSCustomObject]@{'inner'='value4';'innerArray'='value5','value6';'innerHash'=[PSCustomObject]@{'innermost1'='value7';'innermost2'='value8';'innermost3'='value9'}}

    Thanks again to all who contributed.


    • Marked as answer by atscripter Tuesday, February 12, 2019 4:08 PM
    • Edited by atscripter Tuesday, February 12, 2019 4:10 PM
    Tuesday, February 12, 2019 4:08 PM

All replies

  • Does answer #8 in this post help?

    https://stackoverflow.com/questions/22002748/hashtables-from-convertfrom-json-have-different-type-from-powershells-built-in-h

    I ran the code below and got this as a result:

    Name                           Value
    ----                           -----
    outer                          value1
    outerArray                     {value2, value3}
    outerHash                      {innerArray, innerHash, inner}

    function ConvertPSObjectToHashtable
    {
        param (
            [Parameter(ValueFromPipeline)]
            $InputObject
        )
    
        process
        {
            if ($null -eq $InputObject) { return $null }
    
            if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string])
            {
                $collection = @(
                    foreach ($object in $InputObject) { ConvertPSObjectToHashtable $object }
                )
    
                Write-Output -NoEnumerate $collection
            }
            elseif ($InputObject -is [psobject])
            {
                $hash = @{}
    
                foreach ($property in $InputObject.PSObject.Properties)
                {
                    $hash[$property.Name] = ConvertPSObjectToHashtable $property.Value
                }
    
                $hash
            }
            else
            {
                $InputObject
            }
        }
    }
    
    $json = @"
    {
        "outer": "value1",
        "outerArray": [
            "value2",
            "value3"
        ],
        "outerHash": {
            "inner": "value4",
            "innerArray": [
                "value5",
                "value6"
            ],
            "innerHash": {
                "innermost1": "value7",
                "innermost2": "value8",
                "innermost3": "value9"
            }
        }
    }
    "@
    $j = $json | ConvertFrom-Json
    $x = $j | ConvertPSObjectToHashtable


    --- Rich Matheisen MCSE&I, Exchange Ex-MVP (16 years)

    Wednesday, February 6, 2019 4:44 PM
  • Thanks for pitching in Rich! Unfortunately that provides the same truncated output. I am looking for an expanded output as illustrated under "desired effect" above.
    Wednesday, February 6, 2019 5:03 PM
  • The objects are created correctly:

    PS D:\scripts> $json = @"
    >> {
    >>     "outer": "value1",
    >>     "outerArray": [
    >>         "value2",
    >>         "value3"
    >>     ],
    >>     "outerHash": {
    >>         "inner": "value4",
    >>         "innerArray": [
    >>             "value5",
    >>             "value6"
    >>         ],
    >>         "innerHash": {
    >>             "innermost1": "value7",
    >>             "innermost2": "value8",
    >>             "innermost3": "value9"
    >>         }
    >>     }
    >> }
    >> "@ | ConvertFrom-Json
    PS D:\scripts> $json
    
    outer  outerArray       outerHash
    -----  ----------       ---------
    value1 {value2, value3} @{inner=value4; innerArray=System.Object[]; innerHash=}
    
    
    PS D:\scripts> $json.OuterArray
    value2
    value3
    PS D:\scripts> $json.OuterHash
    
    inner  innerArray       innerHash
    -----  ----------       ---------
    value4 {value5, value6} @{innermost1=value7; innermost2=value8; innermost3=value9}
    
    
    PS D:\scripts> $json.OuterHash.innerHash
    
    innermost1 innermost2 innermost3
    ---------- ---------- ----------
    value7     value8     value9
    
    
    PS D:\scripts>


    \_(ツ)_/

    Wednesday, February 6, 2019 5:17 PM
  • jrv - The objects are indeed parsed correctly but my request is specific to output formatting. PowerShell's default behavior is to only display one level down the hash (notice how you had to append .innerHash to display inner content). I want to be able to recursively expand and output all inner hash/array contents without appending .innerContent for each sub-level.
    Wednesday, February 6, 2019 5:29 PM
  • You can use select expand to display the nested contents, but not sure how/if you can leverage it to get your desired results.

    $json | Select-Object -ExpandProperty outerhash

    Wednesday, February 6, 2019 5:42 PM
  • jrv - The objects are indeed parsed correctly but my request is specific to output formatting. PowerShell's default behavior is to only display one level down the hash (notice how you had to append .innerHash to display inner content). I want to be able to recursively expand and output all inner hash/array contents without appending .innerContent for each sub-level.

    That is how PowerShell works.  If you want different output you will need to write a script that does what you need.


    \_(ツ)_/

    Wednesday, February 6, 2019 5:44 PM
  • You can use select expand to display the nested contents, but not sure how/if you can leverage it to get your desired results.

    $json | Select-Object -ExpandProperty outerhash


    Yes, the question here is how to recursively expand the contents without having to specify it for each child object.
    Wednesday, February 6, 2019 5:56 PM
  • jrv - The objects are indeed parsed correctly but my request is specific to output formatting. PowerShell's default behavior is to only display one level down the hash (notice how you had to append .innerHash to display inner content). I want to be able to recursively expand and output all inner hash/array contents without appending .innerContent for each sub-level.

    That is how PowerShell works.  If you want different output you will need to write a script that does what you need.


    \_(ツ)_/

    Exactly! I am specifically here for assistance with the script, the logic is just a little beyond me. I updated my question to make it a little clearer. Thanks for pitching in!
    Wednesday, February 6, 2019 6:00 PM
  • You will need to write a recursive function that detects imbedded objects and decide how to output them (format).  We will not write that for you.  Start writing it and ask specific questions as you progress.


    \_(ツ)_/

    Wednesday, February 6, 2019 6:02 PM
  • The solution to this was graciously provided by iRon on another forum. This entailed using the custom ConvertTo-Expression function to iterate through the JSON block and output a PS custom object for each nested hash/array.

    Command:

    $Properties = @{}
    ($Json | ConvertFrom-Json).PSObject.Properties |
        ForEach-Object {$Properties.($_.Name) = $_.Value |
            ConvertTo-Expression -Expand -1}
    [PSCustomObject]$Properties

    Output:

    outer    outerArray        outerHash                                                                                                                                                          
    -----    ----------        ---------                                                                                                                                                          
    'value1' 'value2','value3' [PSCustomObject]@{'inner'='value4';'innerArray'='value5','value6';'innerHash'=[PSCustomObject]@{'innermost1'='value7';'innermost2'='value8';'innermost3'='value9'}}

    Thanks again to all who contributed.


    • Marked as answer by atscripter Tuesday, February 12, 2019 4:08 PM
    • Edited by atscripter Tuesday, February 12, 2019 4:10 PM
    Tuesday, February 12, 2019 4:08 PM