skip to Main Content

I have empty settings.json file

{ 
}

I want to add section with powershell and to look like this:

{
    "ParentObj":  {
                  "ChildProp":  "test"
                  }
}

I use this sample of code to achieve this :

$SettingFile = Get-Content 'c:zsetting.json' -raw -Encoding UTF8 | ConvertFrom-Json 

if (-not $SettingFile.PSObject.Properties['ParentObj']) {
    $SettingFile | Add-Member -MemberType NoteProperty -Name ParentObj -Value @{}
}

if (-not $SettingFile.ParentObj.PSObject.Properties['ChildProp']) {
    Write-Host 'section 1'
    $SettingFile.ParentObj | Add-Member -MemberType NoteProperty -Name 'ChildProp' -Value 'test'
} else {
     Write-Host 'section 2'
    $SettingFile.ParentObj.ChildProp = 'test2'
}

$SettingFile | ConvertTo-Json -Depth 10 | set-content 'c:zsetting.json' -Encoding UTF8

On the first run of the script I always have empty ParentObj without ChildProp although it says it enter in section 1 of if to create child prop


{
    "ParentObj":  {

                  }
}

i have workaround but i want to understand why on the first run ChildProp is not created, what I am misunderstanding about PowerShell behaviour ?

2

Answers


  1. Replace:

    -Value @{}

    with:

    -Value ([pscustomobject]@{})


    @{} creates an empty hashtable rather than a [pscustomobject], and you want the latter.

    By using a hashtable, the subsequent Add-Member call decorated the empty hashtable stored in .ParentObject with a ChildProp ETS NoteProperty property, which was in effect ignored by ConvertTo-Json – only the empty hashtable itself was serialized and – given that serializing a hashtable to JSON means serializing its entries and there none – you ended up with an empty ParentObj property in the output JSON.

    By contrast, a [pscustomobject] instance is entirely composed of NoteType properties that are considered first-class property citizens and therefore all serialize to JSON.

    Login or Signup to reply.
  2. Your issue is when you do -Value @{} instead of -Value ([psobject]::new()), in simple terms:

    $hash = @{}
    $hash | Add-Member -MemberType NoteProperty -Name 'ChildProp' -Value 'test'
    $hash                # is still an empty hash but has been wrapped in PSObject
    $hash.ChildProp      # and a note property has been added to that wrapper
    $hash.GetType()      # but is still a hashtable
    ConvertTo-Json $hash # and json convert only tatgets the underlying object instead of the wrapper psobject
    

    If you’re running PowerShell 7 you might find it easier if you deserialize your Json -AsHashtable, you could approach your code like this:

    $SettingFile = Get-Content 'c:zsetting.json' -Raw -Encoding UTF8 |
        ConvertFrom-Json -AsHashtable
    
    if (-not $settingFile.ContainsKey('ParentObj')) {
        $settingFile['ParentObject'] = [ordered]@{}
    }
    
    $SettingFile['ParentObject']['ChildProp'] =
        -not $SettingFile['ParentObject'].Contains('ChildProp') ? 'test' : 'test2'
    
    $SettingFile | ConvertTo-Json -Depth 10
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search