I'm using PowerShell scripts to amend JSON configuration files. Often, I have to add or update values of specific keys - that is, after I'm done, the key must be in the file with a specific value, but I do not tell (nor care) whether the key was in the file beforehand.
This is how I read my JSON files:
$settings = Get-Content -Raw "$settingsPath" | ConvertFrom-Json
Apparently (as per GetType()
), the result of this is a PSCustomObject
.
Now, to store value 42
in key foo
, I can do one of two things:
A) Update the value:
$settings.foo = 42
But if foo
does not exist, this will throw an exception saying property foo
is unknown.
B) Create the value:
$settings | Add-Member -Name 'foo' -Type NoteProperty -Value 42
But if foo
is already existing, this will throw an exception saying property foo
is already there.
Now, of course I can check whether foo
exists, and put that into a custom function1, but I feel like I'm missing something. Is there no built-in way to achieve this in a single call?
1: Note that the call required to check this, if ($settings.PSobject.Properties.name -match 'foo') {
, is not the most straightforward of calls, either.
But if
foo
is already existing, this will throw an exception saying property foo is already there.
That's what the -Force
switch parameter is for - using it with Add-Member
will suppress the collision error and overwrite the attached instance property anyway:
$settings | Add-Member -Name 'foo' -Type NoteProperty -Value 42 -Force
In PowerShell 7.x you also have the option of parsing the JSON into a hiearachy of ordered hashtables instead of custom objects:
$settings = Get-Content -Raw "$settingsPath" | ConvertFrom-Json -AsHashTable
Now you can update entry values with a simple index access operation:
$settings['foo'] = "whatever"
Note that the call required to check this, if (
$settings.PSobject.Properties.name -match 'foo'
) {, is not the most straightforward of calls, either
The Properties
collection exposed by the psobject
memberset actually provides a Match()
method for exactly this, meaning you can simplify that sort of access slightly:
if ($property = $settings.PSobject.Properties.Match('foo') |Select -First 1) {
$property.Value = 42
}