skip to Main Content

I am looking into iterating json attributes and values from a json file w/out prior knowledge of the schema. I have code that works with many of the json files or downloads I have tested, but draw blanks when it comes to iterating nested values. I have looked at various posts that use Get-Member and .psobject.name and NoteProperty… but all seemed to have prior knowledge of the json content. I tested this

{
  "FoodChoices": [
    {
      "id": 1,
      "name": "TakeOut",
      "variableGroups": [],
      "variables": {
        "Location": {
          "value": "Fast Food"
        },
        "Beverage": {
          "value": "Soda or Lemondade"
        },
        "Tip": {
          "value": "No Way"
        }
      }
    },
    {
      "id": 2,
      "name": "Gourmet",
      "variableGroups": [],
      "variables": {
        "Location": {
          "value": "Nice Resturant"
        },
        "Beverage": {
          "value": "Dirty Martini"
        },
        "Tip": {
          "value": "Maybe"
        }
      }
    }
  ]
}

but had to kludge the iteration

$jfile = "$PSScriptRootFoodChoice.json"

$file = Get-Content $jFile -Raw
$parse = ($file.substring(0,1) -ne "[")
$json = $file | ConvertFrom-Json

$parent = $json | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name
if ($parse -eq $true)
{
   foreach ($p in $parent)
   {
      $d = $json.$p
      if ($d.length -gt 1) { $data = $d }
   }
}
else {$data = $json }
$out = "Key" + "`t" + "Value" + "`n"
$keys = $data | get-member -type properties | Foreach-Object name
foreach ($d in $data)
{
   foreach ($k in $keys)
   {
       $name = $d.$k
       if ($name -match "@")
       {
           $out += "$k`t`n"
           $members = Get-Member -InputObject $name
           foreach ($m in $members)
           {
              if ($m -match "System.Management.Automation.PSCustomObject")
              {
                 $m1 = $m.ToString()
                 $m1 = $m1.Replace("System.Management.Automation.PSCustomObject","") 
                 if ($m1 -match "@")
                 {
                    $m1 = $m1.Replace("@{","")
                    $m1 = $m1.Replace("}","")
                    $m1 = $m1 -split "="
                    $m2 = $m1[0]
                    $m3 = $m1[2]
                    $out += "$m2`t$m3`n"
                 }
                 else {$out += "$name`t$m1`n"}
              }
           }
       }
       else {$out += "$k`t$name`n"}
   }
}
$out
Exit

Hopefully there is a generic way to parse out nested attributes with type of System.Management.Automation.PSCustomObject.

The script outputs

Key Value
id  1
name    TakeOut
variableGroups  
variables   
 Beverage   Soda or Lemondade
 Location   Fast Food
 Tip    No Way
id  2
name    Gourmet
variableGroups  
variables   
 Beverage   Dirty Martini
 Location   Nice Resturant
 Tip    Maybe

2

Answers


  1. I do not see any issue in handling the json. However I think the major way to handle key/value JSON in powershell would be to use convertFrom-Json

    $jsondata = Get-Content D:Scriptsjason_sample.txt
    
    $jsondata | ConvertFrom-Json #Should give you all the child underneath and you can expand also. 
    
    ($jsondata | ConvertFrom-Json).FoodChoices ## should give you all the id, name , etc 
    

    If you are still struggling with it then initially you can handle that with [System.Text.RegularExpressions.Regex]::Unescape($_)

    $jsondata | ConvertTo-Json | % { [System.Text.RegularExpressions.Regex]::Unescape($_) } | Out-File "File.json" -Force
    
    Login or Signup to reply.
  2. Consider the following example.

    function Resolve-Properties($inputObject, $maxLevels=5, $Level=0){
    
      process {
        if($Level -eq 0){
            Write-Host "Key`tValue"
        } else {
            for($i = 0; $i -lt $level; $i++){
                Write-Host "`t" -NoNewline
            }
        }
        
        foreach($prop in $InputObject.PSObject.Properties){
          if($prop.Value.Count -eq 0){
            Write-Host "$($prop.Name)`t[EmptyObj]"
          } elseif($prop.TypeNameOfValue -match "Object"){
            Write-Host "$($prop.Name)`t[Object]"
            if($level -lt $maxLevels){
              foreach($s in $prop.Value){
                Resolve-Properties -InputObject $s -Level ($level + 1)
              }
            }
          } else {
            Write-Host "$($prop.Name)`t$($prop.Value)"
          }
        }
      }
    }
    
    $file = '{
      "FoodChoices": [
        {
          "id": 1,
          "name": "TakeOut",
          "variableGroups": [],
          "variables": {
            "Location": {
              "value": "Fast Food"
            },
            "Beverage": {
              "value": "Soda or Lemondade"
            },
            "Tip": {
              "value": "No Way"
            }
          }
        },
        {
          "id": 2,
          "name": "Gourmet",
          "variableGroups": [],
          "variables": {
            "Location": {
              "value": "Nice Resturant"
            },
            "Beverage": {
              "value": "Dirty Martini"
            },
            "Tip": {
              "value": "Maybe"
            }
          }
        }
      ]
    }'
    
    $parse = ($file.substring(0,1) -ne "[")
    $json = $file | ConvertFrom-Json
    
    $parent = $json | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name
    if ($parse -eq $true){
       foreach ($p in $parent)   {
          $d = $json.$p
          if ($d.length -gt 1) { $data = $d }
       }
    } else {
        $data = $json
    }
    
    Clear
    
    $data | ForEach-Object {
        Resolve-Properties $_
    }
    

    This is based off of the example found here: How to recursively enumerate through properties of object?

    This iterates the Objects and recursively displays them with an additional Tab character added for each level.

    Output

    Key Value
    id  1
    name    TakeOut
    variableGroups  [EmptyObj]
    variables   [Object]
        Location    [Object]
            value   Fast Food
    Beverage    [Object]
            value   Soda or Lemondade
    Tip [Object]
            value   No Way
    Key Value
    id  2
    name    Gourmet
    variableGroups  [EmptyObj]
    variables   [Object]
        Location    [Object]
            value   Nice Resturant
    Beverage    [Object]
            value   Dirty Martini
    Tip [Object]
            value   Maybe
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search