1

I have a json file, simplified version of it looks like this:

 {
  "Location": "EU",
  "Country": {
    "City": "xxx",
    "Town": "xxx"
  },
  "Transport": {
    "Train": "xxx"
  }
}

I have run the ConvertFrom-Json command to convert to PSObject:

$conversion = Get-Content $path | ConvertFrom-Json 

This will give me an output like this:

Location                           : EU
Country                            : @{City="xxx"; Town="xxx"}
Transport                          : @{Train="xxx"}

Question

How can I get the nested values to print out separately? I would want them all to print out like the "Location:EU" one

Is there a different command to ConvertFrom-Json that i should be using for this? Or do I just need to mess around with ConvertFrom-Json command a bit?

To note:

  • I am not just looking for a pretty print out - I would need them all separately for a script I am writing that will be looping through all the key/value pairs
  • I have read about the -Depth flag when using ConvertFrom-Json and does not seem to fix anything here - it seemed this was more relevant for ConvertTo-Json
polo
  • 155
  • 4
  • 11
  • I think the way you have it will work fine, that output is just how powershell displays the nesting. For example if you do `$conversion.Country.City` you will just get `xxx` out. – frankM_DN Oct 18 '22 at 13:15
  • @frankM_DN thanks for replying! strange - that doesn't work for me. It returns nothing – polo Oct 18 '22 at 13:38
  • hmm. I just copied the text that you say is in the json file into a string variable and it worked for me. So maybe something wonky with the json file? I put that text into a file and used `get-content | convertfrom-json` and that worked as well. – frankM_DN Oct 18 '22 at 13:46

1 Answers1

1

In order to report all leaf properties as name-value pairs (i.e. those properties that contain primitive JSON values as opposed to containing nested objects with properties and / or arrays), you need to recursively walk the object graph:

Find helper function Get-LeafProperty below; assuming you have already defined it, you can call it as follows:

@'
  {
    "Location": "EU",
    "Country": {
      "City": "xxx",
      "Town": "xxy"
    },
    "Transport": {
      "Train": "xxz"
    }
  }
'@ | 
  ConvertFrom-Json |
  Get-LeafProperty

Output (the display formatting of [pscustomobject] instances with .Name and .Value properties representing all the leaf properties):

Name     Value
----     -----
Location EU
City     xxx
Town     xxy
Train    xxz

Get-LeafProperty source code:

# Walks a potentially nested [pscustomobject] graph
# as returned by ConvertFrom-Json and outputs all
# leaf properties as name-value custom objects.
function Get-LeafProperty {
  param([Parameter(ValueFromPipeline)] [object] $InputObject)
  process {   
    if ($InputObject -is [array]) { # array as single input object -> recurse
      foreach ($o in $InputObject) { Get-LeafProperty $o }
    }
    else { 
      # Assumed to be a (potentially nested) [pscustomobject] instance:
      # Recursively process its properties.
      foreach ($p in $InputObject.psobject.properties) {
        if ($p.Value -is [array]) { # array -> recurse
          foreach ($o in $p.Value) { Get-LeafProperty $o }
        } elseif ($p.Value -is [System.Management.Automation.PSCustomObject] ) { # nested [pscustomobject] -> recurse
          Get-LeafProperty $p.Value
        } else { # leaf property reached -> output name-value pair
          [pscustomobject] @{ Name = $p.Name; Value = $p.Value }
        }
      }
    }
  }
}

Note: A variant of this function that outputs property name paths (e.g. Country.City) instead of just their names (e.g. City) can be found in this answer.

mklement0
  • 382,024
  • 64
  • 607
  • 775