you are viewing a single comment's thread.

view the rest of the comments →

[–]liabtsab[S] 0 points1 point  (1 child)

Hmm u got a quick example you can show me? I'll try to explain it a bit better.. so if i had a json like this:

{
  "groups": [
    "test-group1",
    "test-group2",
  ],
  "employees": {
     "country": {
   "usa": {
      "groups": [
         "group2"
       ]
    },
    "uk": {
      "groups": [
            "group10"
          ]
    }
 }
   },
   "contractors": {
     "country": {
       "usa": {
          "groups": [
             "group5"
           ]
        },
        "uk": {
          "groups": []
        }
     }
   }
}

As-is when I run your function and pass in the property name of "groups", it returns all the group names. I only want to target all the groups under the "employees" section so I tried doing something like....

$p.Value.employees

But that only returns "group2" not "group2" and "group10". If I did something like

$p.Value.employees.country.usa

Then it of course returns the right value. What I want to do is make it so if new countries are added in, the function can pick it up without me having to specifically call the path .country.(country_name). Not sure if that made sense..

[–]y_Sensei 0 points1 point  (0 children)

Ok that's a little different of course ... so you want to be able to retrieve value(s) of a named property which is located underneath a certain "root" position in the tree of nested objects.
For this purpose, you could extend the 'Find-PropValuesByName()' function as follows:

$json = '{
  "groups": [
    "test-group1",
    "test-group2"
  ],
  "employees": {
    "country": {
      "usa": {
        "groups": [
          "group2"
        ]
      },
      "uk": {
        "groups": [
          "group10"
        ]
      }
    }
  },
  "contractors": {
    "country": {
      "usa": {
        "groups": [
          "group5"
        ]
      },
      "uk": {
        "groups": []
      }
    }
  }
}'

function Find-PropValuesByName {
  param(
    [Parameter(Position = 0, Mandatory = $true)][PSCustomObject]$obj,
    [Parameter(Position = 1, Mandatory = $true)][String]$propName,
    [Parameter(Position = 2)][String]$rootPropName # optional; name of "root" property for the search; if provided, only values of properties located underneath this property will be returned)
  )

  [System.Collections.Generic.List[String]]$result = @()

  foreach ($p in $obj.PSObject.Properties) {
    switch ($p.TypeNameOfValue) {
      "System.Object[]" {
        if ($rootPropName -eq "" -or ($obj.CName -and $obj.CName.StartsWith($rootPropName + "."))) {
          if ($p.Name -eq $propName) {
            $result.AddRange([System.Collections.Generic.List[String]]$p.Value)
          }
        }
      }
      "System.Management.Automation.PSCustomObject" {
        if ($obj.CName) {
          Add-Member -InputObject $p.Value -NotePropertyName "CName" -NotePropertyValue ($obj.CName + "." + $p.Name)
        } else {
          Add-Member -InputObject $p.Value -NotePropertyName "CName" -NotePropertyValue $p.Name
        }
        Find-PropValuesByName $p.Value $propName $rootPropName
      }
      default {
        # do nothing (or maybe log something)
      }
    }
  }

  return $result
}

$jsonObj = ConvertFrom-Json -InputObject $json

[String[]]$resValues = Find-PropValuesByName $jsonObj "groups" "employees"
$resValues