Reputation: 375
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
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
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
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