4

I need a method that gives me all the properties of an object (recursively). It is not known how many sub-objects the transferred object has.

Example object:

$Car = [PSCustomObject] @{
    Tire          = [PSCustomObject] @{
        Color = "Black"
        Count = 4
    }

    SteeringWheel = [PSCustomObject]@{
        Color   = "Blue"
        Buttons = 15
    }
}

Thank you so much!

2

2 Answers 2

10

Use the hidden psobject member set to enumerate the properties, then recurse:

function Resolve-Properties 
{
  param([Parameter(ValueFromPipeline)][object]$InputObject)

  process {
    foreach($prop in $InputObject.psobject.Properties){
      [pscustomobject]@{
        Name = $prop.Name
        Value = $prop.Value
      }
      Resolve-Properties $prop.Value
    }
  }
}

Output (with your sample object hierarchy):

PS C:\> Resolve-Properties $Car

Name          Value
----          -----
Tire          @{Color=Black; Count=4}
Color         Black
Length        5
Count         4
SteeringWheel @{Color=Blue; Buttons=15}
Color         Blue
Length        4
Buttons       15

Be careful, the function shown above makes no effort to protect against infinitely looping recursive references, so:

$a = [pscustomobject]@{b = [pscustomobject]@{a = $null}}
$a.b.a = $a
Resolve-Properties $a

Will send your CPU spinning

Sign up to request clarification or add additional context in comments.

1 Comment

I like this solution a lot, I need to do something similar, except I need to pass in a change to the original object once I find the matching prop + value. So following that example I would want to change all color properties to be red. Ideally it would be nice to update the existing object, but not really married to that thought, certainly open to returning an updated copy of that object.
1

Based on the answer of @Matthias I modified to get a different type of list output since "I needed it that way".

function Get-PropertiesRecursive {
    param (
        [Parameter(ValueFromPipeline)][object]$InputObject,
        [String]$ParentName
    )
    if ($ParentName) {$ParentName +="."}
    foreach ($Property in $InputObject.psobject.Properties) {
        if ($Property.TypeNameOfValue.Split(".")[-1] -ne "PSCustomObject") {
            [pscustomobject]@{
                TypeName = $Property.TypeNameOfValue.Split(".")[-1]
                Property = "$ParentName$($Property.Name)"
                Value = $Property.Value
            }
        } else {
            Get-PropertiesRecursive $Property.Value -ParentName "$ParentName$($Property.Name)"
        }
    }
}

If you call it with the variable name as -ParentName as option you will get this list:

Get-PropertiesRecursive $Car -ParentName '$Car'

TypeName Property                   Value
-------- --------                   -----
String   $Car.Tire.Color            Black
Int32    $Car.Tire.Count            4    
String   $Car.SteeringWheel.Color   Blue 
Int32    $Car.SteeringWheel.Buttons 15   

And just as Matthias I was too lazy to add property-loop protection, it would have blown up that example.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.