1

I have converted a JSON file to a PSObject using:

$json = Get-Content $filepath -Raw | ConvertFrom-Json

An example of what is now in the PSObject:

Value           : Production
MemberType      : NoteProperty
IsSettable      : True
IsGettable      : True
TypeNameOfValue : System.String
Name            : Environment
IsInstance      : True

I know you can get the Value of this by using:

$json.psobject.properties["Environment"].Value

This will return "Production"

Question:

Is there a way to get the Name returned based on the value like how I am able to get the Value returned based on the name as shown above?

I.e. How can i get "Environment" returned?

For background I am writing a script that will loop through all the values and if the values are empty then i need to print the Names.

polo
  • 155
  • 4
  • 11

1 Answers1

0

With Theo's help you've already found the solution, but let me spell it out, with some background information:

# Read a sample object from JSON text.
$fromJson = @'
{
  "Foo": "Bar",
  "Environment": "Production",
  "Other": "Stuff"
}
'@ | ConvertFrom-Json

# Find the name of the property/ies whose value is 'Production'
# -> 'Environment'
$fromJson.psobject.Properties.Where({ $_.Value -eq 'Production' }).Name

Note:

  • The above relies on the intrinsic psobject property that PowerShell exposes on all objects, which is a rich source of reflection, such as on a given object's properties via .psobject.Properties, as well as on the intrinsic .Where() method for filtering (a better-performing, feature-richer alternative to the Where-Object cmdlet).

  • The code only works for top-level properties of the object(s) parsed from JSON. If you need to search an entire object graph, i.e. nested objects for values at any level of the hierarchy, more effort is needed.

The following example assumes that function Get-PropertyPathByValue has already been defined (see below):

# Read a *nested* sample object from JSON text.
$fromJson = @'
{
  "Foo": "Bar",
  "Nested": {
    "More": "Stuff",
    "Environment": "Production"
  },
  "Other": "Stuff"
}
'@ | ConvertFrom-Json

# Find the value 'Production' anywhere in the object hierarchy,
# and return the matching property's name *path* (dot notation).
# -> 'Nested.Environment'
$fromJson | Get-PropertyPathByValue -Value 'Production'

Get-PropertyPathByValue source code - note the limitation on what types of values can be searched for:

# Finds a *simple* value in the object graphs given and returns the path of 
# matching properties in dot notation (e.g., 'foo.bar`).
# Note: *Simple* means a *single* (non-collection) value that is either:
#  * a string or
#  * an instance of a .NET primitive or similar type (numbers, dates).
function Get-PropertyPathByValue {
  param([Parameter(ValueFromPipeline, Mandatory)] [AllowNull()]  [object] $InputObject, [Parameter(Mandatory)] [AllowNull()] $Value, [string] $NamePath)
  process {   
    if ($null -eq $InputObject -or $InputObject.GetType().IsPrimitive -or $InputObject.GetType() -in [string], [datetime], [datetimeoffset], [decimal], [bigint]) {
      # A null-like value or a primitive / quasi-primitive type -> output.
      if ($Value -eq $InputObject) { return $NamePath }
    }
    elseif ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [System.Collections.IDictionary]) {
      # A collection of sorts (other than a string or dictionary (hash table)), 
      # recurse on its elements.
      $i = 0
      foreach ($o in $InputObject) { Get-PropertyPathByValue $o $Value ($NamePath + '[' + $i++ + ']') }
    }
    else { 
      # A non-quasi-primitive scalar object or a dictionary:
      # enumerate its properties / entries.
      $props = if ($InputObject -is [System.Collections.IDictionary]) { $InputObject.GetEnumerator() } else { $InputObject.psobject.properties }
      $sep = '.' * ($NamePath -ne '')
      foreach ($p in $props) {
        Get-PropertyPathByValue $p.Value $Value ($NamePath + $sep + $p.Name)
      }
    }
  }
}
mklement0
  • 382,024
  • 64
  • 607
  • 775