thefern
thefern

Reputation: 367

How to get key value pairs from json property with Powershell

I am stuck on how to get key value pairs from a json file dynamically meaning without knowing the key value in advance.

I have this sample json file, in the real application I have about 20 json files with a couple of thousand automated test cases:

{
    "runOnMachines": "SERVER-01",
    "cases": [
    {
        "testName": "Google Chrome Install 84.0.4147.89",
        "testDescription": "Verifies Google Chrome is Installed 84.0.4147.89",
        "testFunction": "Find-ProgramVersion",
        "args": [
          {
            "programName" : "Firefox",
            "version"     : "79.0"
          }
        ],
        "expectedResult": "true"
      },
      {
        "testName": "Tera Term 4.105",
        "testDescription": "Tera Term 4.105",
        "testFunction": "Find-ProgramVersion",
        "args": [
          {
            "programName" : "Tera Term",
            "version"     : "4.105"     
          }
        ],
        "expectedResult": "true"
      }
    ]
}

Find-ProgramVersion is a helper function which searches for a program installed in control panel / programs installed through the registry, it returns true or false. (More info on that here Winster Is part of an automated framework I built to test virtual machines on servers.

Long story short, I have this ugly code, that I am trying to clean up, but I can't find how to extract my args dynamically from a json file. As of now, each function I write on Winster module I have to come on this script and add it manually with the correct json properties.

if($jsonData[$i].testFunction -eq "Find-ProgramVersion")
{
    $command = $jsonData[$i].testFunction + " " + $jsonData[$i].args.programName + " " + 
    $jsonData[$i].args.version
}

if($jsonData[$i].testFunction -eq "Find-ProgramVersionGrep")
{
    $command = $jsonData[$i].testFunction + " " + $jsonData[$i].args.programName + " " + 
    $jsonData[$i].args.version
}

I've tried casting jsonData[$i].args to array, I've also tried using Name and Value from PsObject.Properties but that gives also other values I don't need inherited from PsObject


for($i=0; $i -lt $jsonData.Count; $i++)
{ 
    $jsonData[$i].args.PSObject.Properties | ForEach-Object {
        $_.Name
        $_.Value
    }
}

Gives me:

Count
1
Length
1
LongLength
1
Rank
1
SyncRoot

programName version
----------- -------
Firefox     79.0   
IsReadOnly
False
IsFixedSize
True
IsSynchronized
False
Count
1
Length
1
LongLength
1
Rank
1
SyncRoot
Tera Term   4.105  
IsReadOnly
False
IsFixedSize
True
IsSynchronized
False

What I am hoping to get from jsonData[$i].args is some kind of iterable, where I can use forloop, but I haven't been able to make the below PsObject usable. And witthout knowing args names in advance since some functions have different numbers of args.

@{programName=Firefox; version=79.0} @{programName=Tera Term; version=4.105}

Upvotes: 3

Views: 1179

Answers (1)

mklement0
mklement0

Reputation: 440162

(@'
{
  "runOnMachines": "SERVER-01",
  "cases": [
  {
      "testName": "Google Chrome Install 84.0.4147.89",
      "testDescription": "Verifies Google Chrome is Installed 84.0.4147.89",
      "testFunction": "Find-ProgramVersion",
      "args": [
        {
          "programName" : "Firefox",
          "version"     : "79.0"
        }
      ],
      "expectedResult": "true"
    },
    {
      "testName": "Tera Term 4.105",
      "testDescription": "Tera Term 4.105",
      "testFunction": "Find-ProgramVersion",
      "args": [
        {
          "programName" : "Tera Term",
          "version"     : "4.105"     
        }
      ],
      "expectedResult": "true"
    }
  ]
}
'@ | ConvertFrom-Json).cases | ForEach-Object {
  $_.testFunction + ' ' + (
    $_.args.ForEach( { 
        $_.PSObject.Properties.Value.ForEach( {
            if ($_.contains(' ')) {
              # contains spaces -> double-quote
              '"{0}"' -f $_
            }
            else {
              $_
            }
          })
      })
  ) -join ' '
}

The above returns the following:

Find-ProgramVersion Firefox 79.0
Find-ProgramVersion "Tera Term" 4.105

More work is needed if there are values with embedded " chars.

  • $_.args.ForEach iterates over all elements of the args array.

  • $_.PSObject.Properties.Value.ForEach iterates over all property values of each element.

  • $_.contains(' ') tests each property value for the presence of at least one space character, in which case the value is enclosed in double quotes ('"{0}"' -f $_) in the overall command line that is being constructed (via the string constructed from the space-joined values with -join ' ').

Upvotes: 5

Related Questions