1

The problem

I need to use powershell to update all instances of a property called sourceList in a large exported JSON file, however the structure of the JSON is not consistent with each export, with the property occuring at various depths:

Example structure of JSON

{
    "rows": [
        {
            "controls": [
                {
                    "properties": {
                        "sourceList": "I NEED TO CHANGE THIS"
                    }
                }
            ]
        },
        {
            "controls": [
                {
                    "properties": {
                        "rows": [
                            {
                                "controls": [
                                    {
                                        "properties": {
                                            "sourceList": "ALSO THIS, BUT IT'S MUCH DEEPER"
                                        }
                                    }
                                ]
                            }
                        ]
                    }
                }
            ]
        }
    ]
}

The JSON file is from a form building tool, so different form designs (e.g. putting fields in group container) can cause the depth to change drastically.

Current Code

$formObj = Get-Content -Raw -Path $form | ConvertFrom-Json
# Find and update all instances of sourceList
$formObj | ConvertTo-Json -Depth 100 | Set-Content $form

The actual conversion to and from JSON works fine, and I've successfully changed some other properties that have a reliable structure, my issue is finding and updating a named property with no way of knowing at what depth it will occur.

Hanayou
  • 13
  • 2

2 Answers2

0

For this you will need to create a recursive function.
To make things easier, I recommend you to use the ConvertFrom-Json -AsHashTable parameter which will return [HashTable] objects rather than [PSCustomObject] Objects

Function Set-Recurse ($Object, $Key, $Value) {
    if ($Object -is [HashTable]) {
        if ($Object.ContainsKey($Key)) { $Object[$Key] = $Value }
        $Object.get_Values() | ForEach-Object { Set-Recurse $_ $Key $Value}
    }
    elseif ($Object -is [Array]) {
        $Object | ForEach-Object { Set-Recurse $_ $Key $Value}
    }
}

Usage:

$formObj = ConvertFrom-Json -AsHashTable '{
    "rows": [
        {
            "controls": [
                 ...
    ]
}'

Set-Recurse $formObj sourceList 'New Value'

$formObj | ConvertTo-Json -Depth 100
iRon
  • 20,463
  • 10
  • 53
  • 79
0

Why not just do this...

Select-String -Path '.\FormTool.txt' -Pattern 'sourceList' -Context 0
# Results
<#
FormTool.txt:7:                        "sourceList": "I NEED TO CHANGE THIS"
FormTool.txt:21:                                            "sourceList": "ALSO THIS, BUT IT'S MUCH DEEPER"
#>

Then modify at the line number or string match.

(Select-String -Path '.\FormTool.txt' -Pattern 'sourceList' -Context 0) -replace '\:\s".*', ': "Repalced with this stuff"'
# Results
<#
D:\Scripts\FormTool.txt:7:                        "sourceList": "Repalced with this stuff"
D:\Scripts\FormTool.txt:21:                                            "sourceList": "Repalced with this stuff"
#>
postanote
  • 15,138
  • 2
  • 14
  • 25