user3364161
user3364161

Reputation: 375

Add nested properties to a PowerShell object

I'm working with a script in PowerShell that updates JSON data, accessing an modifying data that's 3 layers deep. The general flow is:

$obj = Get-Content -Raw -Path $pathstring | ConvertFrom-Json
$obj.prop1.prop2.prop3.prop4 = "test"
$outjson = ConvertTo-Json -InputObject $obj -Depth 5
Set-Content -Path $pathstring -Value $outjson

This works when the property already exists. However, in some cases $obj.prop1.prop2.prop3.prop4 does not exist. I want to add a series of nested properties to a PowerShell object, and then convert that to JSON to create it.

Is that possible/how is that done/is there a better way to add JSON values to something in PowerShell?

Edit: I'm currently running

if(Get-Member -inputobject $js.prop1 -name "prop2" -Membertype Properties)

to test if the property exists, and if prop2 doesn't exist then I need to create all the properties.

Upvotes: 1

Views: 7633

Answers (3)

SpaceGhost440
SpaceGhost440

Reputation: 579

@J.Peter I really liked your solution, but I needed to be able to provide a way to add properties in the name with periods. so I made a slight mod to yours. I added an escape character to the parameters, that gets replaced in the string with a period.

Edit: another rewrite. Got rid of the recursion, and now it can handle creating very complex objects as well as having "." in the property names. Was so happy with the changes I made a gist for it https://gist.github.com/tcartwright/72cac052e1f8058abed1f7028f674a10 with credits.

function Add-NoteProperty {
    param(
        $InputObject,
        $Property,
        $Value,
        [switch]$Force,
        [char]$escapeChar = '#'
    )
    process {
        $path = $Property -split "\."
        $obj = $InputObject
        # loop all but the very last property
        for ($x = 0; $x -lt $path.count -1; $x ++) {
            $propName = $path[$x] -replace $escapeChar, '.'
            if (!($obj | Get-Member -MemberType NoteProperty -Name $propName)) {
                $obj | Add-Member NoteProperty -Name $propName -Value (New-Object PSCustomObject) -Force:$Force.IsPresent
            }
            $obj = $obj.$propName
        }
        $propName = ($path | Select-Object -Last 1) -replace $escapeChar, '.'
        if (!($obj | Get-Member -MemberType NoteProperty -Name $propName)) {
            $obj | Add-Member NoteProperty -Name $propName -Value $Value -Force:$Force.IsPresent
        }
    }
}


$obj = [PSCustomObject]@{}

Add-NoteProperty -InputObject $obj -Property "Person.Name.First" -Value "Tim"
Add-NoteProperty -InputObject $obj -Property "Person.Name.Last" -Value "C"
Add-NoteProperty -InputObject $obj -Property "Person.Age" -Value "Old"
Add-NoteProperty -InputObject $obj -Property "Person.Address.City" -Value "Houston"
Add-NoteProperty -InputObject $obj -Property "Person.Address.State" -Value "Texas"
$obj | ConvertTo-JSON

Which results in:

{
    "Person":  {
                   "Name":  {
                                "First":  "Tim",
                                "Last":  "C"
                            },
                   "Age":  "Old",
                   "Address":  {
                                   "City":  "Houston",
                                   "State":  "Texas"
                               }
               }
}

Upvotes: 3

sipho102
sipho102

Reputation: 191

I recently encountered a similiar problem where I needed to add nested properties to objects so I wrote a recursive function for it.

function Add-NoteProperty {
    param(
        $InputObject,
        $Property,
        $Value,
        [switch]$Force
    )
    process {
        [array]$path = $Property -split "\."
        If ($Path.Count -gt 1) {
            #go in to recursive mode
            $Obj = New-Object PSCustomObject
            Add-NoteProperty -InputObject $Obj -Property ($path[1..($path.count - 1)] -join ".") -Value $Value
        }
        else {
            #last node
            $Obj = $Value
        }
        $InputObject | Add-Member NoteProperty -Name $path[0] -Value $Obj -Force:$Force
    }
}

Usage example:

$obj = [PSCustomObject]@{
    prop1 = "1"
    prop2 = "2"
}
Add-NoteProperty -InputObject $obj -Property "prop3.nestedprop31.nestedprop311" -Value "somevalue"
$obj | ConvertTo-JSON
<#Should give you this 
{
    "prop1":  "1",
    "prop2":  "2",
    "prop3":  {
                  "subprop":  {
                                  "asdf":  "3"
                              }
              }
}
#>

Upvotes: 1

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200193

If a property doesn't exist you need to add it, otherwise you can't assign a value to it:

$obj.prop1.prop2.prop3 | Add-Member -Type NoteProperty -Name 'prop4' -Value 'test'

Upvotes: 1

Related Questions