Search code examples
jsonpowershell

Powershell update object property value not as expect


I have one Json file and I just want to update some specified property value instead of all the same value in the json file.

But the current situation is that I can replace the specified attribute value, but it will have an additional structure.

My test Json file like:

{
    "$schema":  "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion":  "1.0.0.0",
    "resources":  [
                      {
                          "apiVersion":  "2016-06-01",
                          "kind":  "V2",
                          "properties":  {
                                             "displayName":  "azuredatafactory",
                                             "overallStatus":  "Ready",
                                             "connectionState":  "Enabled",
                                             "customParameterValues":  {
                                                                       },
                                             "alternativeParameterValues":  {
                                                                            },
                                             "parameterValueType":  "Alternative",
                                             "createdTime":  "2024-06-27T09:03:39.9477Z",
                                             "changedTime":  "2024-06-27T09:03:39.9477Z",
                                             "testLinks":  [

                                                           ],
                                             "connectionRuntimeUrl":  "https://89ad7e55624ad1be.08.common.logic-eastasia.azure-apihub.net/apim/azuredatafactory/9fed9f23xxxxxa34f23d186b"
                                         },
                          "id":  "/subscriptions/e1c6546xxxxx218a/resourceGroups/rxxxxxl-ietl01/providers/Microsoft.Web/connections/azuredatafactory",
                          "name":  "azuredatafactory",
                          "type":  "Microsoft.Web/connections",
                          "location":  "eastasia",
                          "tags":  {
                                       "CreatedOnDate":  "2024-06-27T09:03:39.3814086Z",
                                       "Environment":  "D"
                                   }
                      }
                  ]
}

I just want to update the "displayName": "azuredatafactory" under the node resources.properties and the "name": "azuredatafactory" under the node resources.

My test powershell scripts like below:

$RevertTypeForJson = Get-Content -Path "<pathtoMyJsonfiles>\MyTestJson.json" -Raw | ConvertFrom-Json

$RevertTypeForJson.resources | ForEach-Object {
    $_.name = @($_.name -replace "$(VariableForAzuredatafactory)", "$(VariableForAzuredatafactory)_NewValue")
    $_.properties.displayName = @($_.properties.displayName -replace "$(VariableForAzuredatafactory)", "$(VariableForAzuredatafactory)_NewValue")
}

$NewRevertTypeForJson = $RevertTypeForJson | ConvertTo-Json -Depth 100
Write-Host "$NewRevertTypeForJson"

However, the output given is:

                       "properties":  {
                                          "displayName":  [
                                                              "azuredatafactory_NewVlaue"

                                                          ],

and

                   "name":  [
                                "azuredatafactory_SIT"
                            ],

Instead of "displayName": "azuredatafactory_NewVlaue", and "name": "azuredatafactory_NewVlaue",

How to update my scripts to achieve the expect result "displayName": "azuredatafactory_NewVlaue", and "name": "azuredatafactory_NewVlaue",?

Note: I cannot replace with global variables. I know it would be simple, but you can see that the ID value also contains the same value, which cannot be changed, so I must modify the value under specific properties.


Solution

  • PowerShell is generally pretty flexible when it comes to output typing - if a pipeline outputs 0 objects, any assignment target will receive $null, with exactly 1 object you get just that 1 object, and with 2 or more PowerShell will wrap the output in an array.

    This works out well most of the time, but sometimes you want an array, regardless of the number of objects a particular pipeline or expression evaluates to.

    Enter the array subexpression operator @(...)

    @(...) will cause PowerShell to always wrap the concatenated output from any and all top-level statements nested inside it in an array, which is why you get the additional [...] around the value in the final JSON - [...] is the JSON notation for an array.

    Remove the @(...)'s and it'll work as expected:

    $RevertTypeForJson.resources | ForEach-Object {
        $_.name = $_.name -replace "$(VariableForAzuredatafactory)", "$(VariableForAzuredatafactory)_NewValue"
        $_.properties.displayName = $_.properties.displayName -replace "$(VariableForAzuredatafactory)", "$(VariableForAzuredatafactory)_NewValue"
    }