Программно найти и удалить объект в объекте JSON

TL; DR Как мне программно найти объект, который может не находиться в одном и том же месте для каждого файла, и удалить его?

Хорошо, если я точно знаю, где объект будет находиться внутри JSON, но если он меняет местоположение, это сложно написать в сценарии. На данный момент мы программно создаем шаблон ARM и отправляем его в Azure, но прежде чем мы это сделаем, мы сравниваем его, чтобы увидеть, что версия в облаке отличается от только что сгенерированного файла, и если это так, либо заменяем его, либо создаем новый на основе по его версии.

Проблема заключается в том, что спецификация шаблона создается с новой версией Bicep, которая затем вводит эту информацию в файл JSON, который затем корректирует значения version и templateHash. К сожалению, я не могу предотвратить это.

          "metadata": {
            "_generator": {
              "name": "bicep",
              "version": "0.4.1008.15138",
              "templateHash": "17593852815978663805"
            }

Раньше я делал Compare-Object для сравнения двух файлов после превращения их в объекты PowerShell, но когда пришло бинарное изменение, эта идея была отброшена. Затем я начал искать более сложное сравнение PowerShell, где оно будет игнорировать строки на основе шаблонов, но сегодня утром это не удалось из-за какой-то случайной ошибки, которую я не могу диагностировать, потому что она находится в конвейере Azure DevOps.

Write-Host "`n`n##[debug]?`tLooking for changes  ?"
$bicepAlteredLines  = @()
$templateSpecChange = $false
$patterns           = @(
    '\"version\"'
    '\"templateHash\"'
)


# newFile (${currentDir}.json) goes into old oldFile (portal.json)
$compare = Compare-Object `
    -ReferenceObject  $(Get-Content -Path "./portal.json") `
    -DifferenceObject $(Get-Content -Path "./${currentDir}.json")

# find the values where new goes into old
foreach($result in ($compare | Where-Object { $_.SideIndicator -eq "=>" })) {

    # loop over patterns that should be excluded because of bicep binary update
    foreach($pattern in $patterns) {

    # for each bicep binary metadata pattern, check to see if the difference line matches that pattern
        if ($result.InputObject -match $pattern) {

            # create variable of old oldFile which is referenced on the same line
            $comparedResult = $compare |
                Where-Object {
                    ($_.SideIndicator -eq "< = ") -and
                    ($_.InputObject.ReadCount -eq $result.InputObject.Readcount)
                }

            # check to see if the variable also contains the pattern that should be excluded
            if ($comparedResult.InputObject -match $pattern) {

                $selectSearch = Select-String -Path "./${currentDir}.json" -Pattern $pattern -Context 2 |
                    Where-Object {
                        $_.LineNumber -eq $result.InputObject.Readcount
                    }

                # validate if the pattern relates to bicep and not just random string that looks like what we want
                foreach($item in $selectSearch) {

                    # we do this by checking the lines above the pattern, as this will contain the word 'bicep':
                    # "metadata": {
                    #     "_generator": {
                    #       "name": "bicep",
                    #       "version": "0.4.1008.15138",                <- if this line was the pattern, 1 up contains 'bicep'
                    #       "templateHash": "9914162448113979868"       <- if this line was the pattern, 2 up contains 'bicep'
                    #     }
                    foreach($bicepCheck in $item.Context.PreContext) {
                        if ($bicepCheck -match "bicep") {

                            # if 'bicep' has been found, add array for readout later
                            $bicepAlteredLines += $item.LineNumber
                            Write-Host "Bicep binary change found at line $($item.LineNumber) for pattern ${pattern}. Adding to ignore list."
                        }
                        else {
                            # if the variable doesn't contain 'bicep', then obviously there's been a change in the JSON layout
                            $templateSpecChange = $true
                        }
                    }
                }
            }
            else {
                # if the variable doesn't contain the pattern, then obviously there's been a change in the JSON layout
                $templateSpecChange = $true
            }
        }
        else {
            # if the variable doesn't contain the pattern, then obviously there's been a change in the JSON layout
            $templateSpecChange = $true
        }
    }
}


Write-Host "`nThe following lines are ignored due Bicep binary change:"
$bicepAlteredLines | Sort-Object -Unique

Write-Host "`n`n##[debug]?`tDifference found in file comparison = ${templateSpecChange}"

Так что я хотел бы либо;

  • игнорировать метаданные и сравнивать только окружающую информацию
  • полностью удалить объект метаданных во всех экземплярах, которые он разместил (идеальное решение)
{
  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "metadata": {
    "_generator": {
      "name": "bicep",
      "version": "0.4.1111.15138",
      "templateHash": "asdfasdfasdf"
    }
  },
  "parameters": {
    "p_vnetPeeringsCompute": {
      "type": "array",
      "metadata": {
        "description": "List of peerings to the virtual network."
      }
    },
    "p_vnetPeeringsStorage": {
      "type": "array",
      "metadata": {
        "description": "List of peerings to the virtual network."
      }
    },
    "p_vnetPeeringsLinkFile": {
      "type": "array",
      "metadata": {
        "description": "List of peerings to the virtual network."
      }
    },
    "p_tags": {
      "type": "object",
      "defaultValue": {},
      "metadata": {
        "description": "List of tags applied to resources."
      }
    }
  },
  "functions": [],
  "variables": {
    "v_longLocation": "uksouth",
    "v_shortLocation": "uks",
    "v_templateDescription": "Azure Private DNS Template Spec",
    "v_templateDisplayName": "privateDns",
    "v_templateName": "privateDns",
    "v_templateVersion": "2.0.0",
    "v_templateTags": {
      "tsName": "[variables('v_templateName')]",
      "tsVersion": "[variables('v_templateVersion')]"
    },
    "v_tags": "[union(parameters('p_tags'), variables('v_templateTags'))]"
  },
  "resources": [
    {
      "type": "Microsoft.Resources/resourceGroups",
      "apiVersion": "2021-01-01",
      "name": "[format('{0}-{1}-compute-rsg', variables('v_shortLocation'), subscription().displayName)]",
      "location": "[variables('v_longLocation')]",
      "tags": "[variables('v_tags')]"
    },
    {
      "type": "Microsoft.Resources/resourceGroups",
      "apiVersion": "2021-01-01",
      "name": "[format('{0}-{1}-link-rsg', variables('v_shortLocation'), subscription().displayName)]",
      "location": "[variables('v_longLocation')]",
      "tags": "[variables('v_tags')]"
    },
    {
      "type": "Microsoft.Resources/resourceGroups",
      "apiVersion": "2021-01-01",
      "name": "[format('{0}-{1}-storage-rsg', variables('v_shortLocation'), subscription().displayName)]",
      "location": "[variables('v_longLocation')]",
      "tags": "[variables('v_tags')]"
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2020-06-01",
      "name": "privateCompute",
      "resourceGroup": "[format('{0}-{1}-compute-rsg', variables('v_shortLocation'), subscription().displayName)]",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "mode": "Incremental",
        "parameters": {
          "p_tags": {
            "value": "[variables('v_tags')]"
          },
          "p_vnetPeeringsCompute": {
            "value": "[parameters('p_vnetPeeringsCompute')]"
          }
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "metadata": {
            "_generator": {
              "name": "bicep",
              "version": "0.4.1008.15138",
              "templateHash": "17593852815978663805"
            }
          },
          "parameters": {
            "p_tags": {
              "type": "object",
              "defaultValue": {},
              "metadata": {
                "description": "List of tags applied to resources."
              }
            },
            "p_vnetPeeringsCompute": {
              "type": "array",
              "metadata": {
                "description": "List of peerings to the virtual network."
              }
            }
          },
          "functions": [],
          "resources": [
            {
              "type": "Microsoft.Network/privateDnsZones",
              "apiVersion": "2020-06-01",
              "name": "compute.bld.local",
              "tags": "[parameters('p_tags')]",
              "location": "Global"
            },
            {
              "copy": {
                "name": "vnl",
                "count": "[length(parameters('p_vnetPeeringsCompute'))]"
              },
              "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
              "apiVersion": "2020-06-01",
              "name": "[format('{0}/{1}', 'compute.bld.local', last(split(parameters('p_vnetPeeringsCompute')[copyIndex()].id, '/')))]",
              "tags": "[parameters('p_tags')]",
              "location": "Global",
              "properties": {
                "virtualNetwork": {
                  "id": "[parameters('p_vnetPeeringsCompute')[copyIndex()].id]"
                },
                "registrationEnabled": false
              },
              "dependsOn": [
                "[resourceId('Microsoft.Network/privateDnsZones', 'compute.bld.local')]"
              ]
            }
          ]
        }
      },
      "dependsOn": [
        "[subscriptionResourceId('Microsoft.Resources/resourceGroups', format('{0}-{1}-compute-rsg', variables('v_shortLocation'), subscription().displayName))]"
      ]
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2020-06-01",
      "name": "privateLink",
      "resourceGroup": "[format('{0}-{1}-link-rsg', variables('v_shortLocation'), subscription().displayName)]",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "mode": "Incremental",
        "parameters": {
          "p_vnetPeeringsLinkFile": {
            "value": "[parameters('p_vnetPeeringsLinkFile')]"
          },
          "p_tags": {
            "value": "[variables('v_tags')]"
          }
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "metadata": {
            "_generator": {
              "name": "bicep",
              "version": "0.4.1008.15138",
              "templateHash": "14603239311913824090"
            }
          },
          "parameters": {
            "p_vnetPeeringsLinkFile": {
              "type": "array",
              "metadata": {
                "description": "List of peerings to the virtual network."
              }
            },
            "p_tags": {
              "type": "object",
              "defaultValue": {},
              "metadata": {
                "description": "List of tags applied to resources."
              }
            }
          },
          "functions": [],
          "resources": [
            {
              "type": "Microsoft.Network/privateDnsZones",
              "apiVersion": "2020-06-01",
              "name": "[format('privatelink.file.{0}', environment().suffixes.storage)]",
              "tags": "[parameters('p_tags')]",
              "location": "Global"
            },
            {
              "copy": {
                "name": "vnl",
                "count": "[length(parameters('p_vnetPeeringsLinkFile'))]"
              },
              "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
              "apiVersion": "2020-06-01",
              "name": "[format('{0}/{1}', format('privatelink.file.{0}', environment().suffixes.storage), last(split(parameters('p_vnetPeeringsLinkFile')[copyIndex()].id, '/')))]",
              "tags": "[parameters('p_tags')]",
              "location": "Global",
              "properties": {
                "virtualNetwork": {
                  "id": "[parameters('p_vnetPeeringsLinkFile')[copyIndex()].id]"
                },
                "registrationEnabled": false
              },
              "dependsOn": [
                "[resourceId('Microsoft.Network/privateDnsZones', format('privatelink.file.{0}', environment().suffixes.storage))]"
              ]
            },
            {
              "type": "Microsoft.Network/privateDnsZones",
              "apiVersion": "2020-06-01",
              "name": "[format('privatelink{0}', environment().suffixes.sqlServerHostname)]",
              "tags": "[parameters('p_tags')]",
              "location": "Global"
            }
          ]
        }
      },
      "dependsOn": [
        "[subscriptionResourceId('Microsoft.Resources/resourceGroups', format('{0}-{1}-link-rsg', variables('v_shortLocation'), subscription().displayName))]"
      ]
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2020-06-01",
      "name": "privateStorage",
      "resourceGroup": "[format('{0}-{1}-storage-rsg', variables('v_shortLocation'), subscription().displayName)]",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "mode": "Incremental",
        "parameters": {
          "p_tags": {
            "value": "[variables('v_tags')]"
          },
          "p_vnetPeeringsStorage": {
            "value": "[parameters('p_vnetPeeringsStorage')]"
          }
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "metadata": {
            "_generator": {
              "name": "bicep",
              "version": "0.4.1008.15138",
              "templateHash": "12131108274222647600"
            }
          },
          "parameters": {
            "p_tags": {
              "type": "object",
              "defaultValue": {},
              "metadata": {
                "description": "List of tags applied to resources."
              }
            },
            "p_vnetPeeringsStorage": {
              "type": "array",
              "metadata": {
                "description": "List of peerings to the virtual network."
              }
            }
          },
          "functions": [],
          "resources": [
            {
              "type": "Microsoft.Network/privateDnsZones",
              "apiVersion": "2020-06-01",
              "name": "storage.bld.local",
              "tags": "[parameters('p_tags')]",
              "location": "Global"
            },
            {
              "copy": {
                "name": "vnl",
                "count": "[length(parameters('p_vnetPeeringsStorage'))]"
              },
              "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
              "apiVersion": "2020-06-01",
              "name": "[format('{0}/{1}', 'storage.bld.local', last(split(parameters('p_vnetPeeringsStorage')[copyIndex()].id, '/')))]",
              "tags": "[parameters('p_tags')]",
              "location": "Global",
              "properties": {
                "virtualNetwork": {
                  "id": "[parameters('p_vnetPeeringsStorage')[copyIndex()].id]"
                },
                "registrationEnabled": false
              },
              "dependsOn": [
                "[resourceId('Microsoft.Network/privateDnsZones', 'storage.bld.local')]"
              ]
            }
          ]
        }
      },
      "dependsOn": [
        "[subscriptionResourceId('Microsoft.Resources/resourceGroups', format('{0}-{1}-storage-rsg', variables('v_shortLocation'), subscription().displayName))]"
      ]
    }
  ]
}

На данный момент я знаю, что он находится в 2 стандартных местах, но я не уверен, появится ли он в других.

➜ $asdf.resources.properties.template.metadata

_generator
----------
@{name=bicep; version=0.4.1008.15138; templateHash=17593852815978663805}
@{name=bicep; version=0.4.1008.15138; templateHash=14603239311913824090}
@{name=bicep; version=0.4.1008.15138; templateHash=12131108274222647600}

compare
➜ $asdf.metadata

_generator
----------
@{name=bicep; version=0.4.1111.15138; templateHash=asdfasdfasdf}

Было бы лучше, если бы в PowerShell была возможность найти все экземпляры объектов с именем metadata и удалить их, но я не могу найти такую ​​опцию в PowerShell. Любые мысли/идеи были бы замечательны.

Прежде чем кто-либо упомянет, что я должен просто удалить все экземпляры $asdf.resources.properties.template.metadata и $asdf.metadata, мне интересно, как искать любые экземпляры *.metadata, которые могут быть/могут быть в других местах, которые могут появиться или не появиться. Скорее «искать все *.metadata и удалять из объекта, где бы он ни находился».

Вы ищете решение с использованием процессора JSON командной строки jq или библиотеки JavaScript jQuery?

pmf 31.03.2022 11:05

Либо PowerShell, либо JQ. Не JQuery.

Beefcake 31.03.2022 11:12
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
1
2
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Поскольку jq помечен, вы можете использовать walk для обхода документа JSON, и если он встречает объект, применить del для удаления любого поля .metadata:

jq 'walk(if type == "object" then del(.metadata) else . end)' file.json
{
  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "p_vnetPeeringsCompute": {
      "type": "array"
    },
    "p_vnetPeeringsStorage": {
      "type": "array"
    },
    "p_vnetPeeringsLinkFile": {
      "type": "array"
    },
    "p_tags": {
      "type": "object",
      "defaultValue": {}
    }
  },
  "functions": [],
  "variables": {
    "v_longLocation": "uksouth",
    "v_shortLocation": "uks",
    "v_templateDescription": "Azure Private DNS Template Spec",
    "v_templateDisplayName": "privateDns",
    "v_templateName": "privateDns",
    "v_templateVersion": "2.0.0",
    "v_templateTags": {
      "tsName": "[variables('v_templateName')]",
      "tsVersion": "[variables('v_templateVersion')]"
    },
    "v_tags": "[union(parameters('p_tags'), variables('v_templateTags'))]"
  },
  "resources": [
    {
      "type": "Microsoft.Resources/resourceGroups",
      "apiVersion": "2021-01-01",
      "name": "[format('{0}-{1}-compute-rsg', variables('v_shortLocation'), subscription().displayName)]",
      "location": "[variables('v_longLocation')]",
      "tags": "[variables('v_tags')]"
    },
    {
      "type": "Microsoft.Resources/resourceGroups",
      "apiVersion": "2021-01-01",
      "name": "[format('{0}-{1}-link-rsg', variables('v_shortLocation'), subscription().displayName)]",
      "location": "[variables('v_longLocation')]",
      "tags": "[variables('v_tags')]"
    },
    {
      "type": "Microsoft.Resources/resourceGroups",
      "apiVersion": "2021-01-01",
      "name": "[format('{0}-{1}-storage-rsg', variables('v_shortLocation'), subscription().displayName)]",
      "location": "[variables('v_longLocation')]",
      "tags": "[variables('v_tags')]"
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2020-06-01",
      "name": "privateCompute",
      "resourceGroup": "[format('{0}-{1}-compute-rsg', variables('v_shortLocation'), subscription().displayName)]",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "mode": "Incremental",
        "parameters": {
          "p_tags": {
            "value": "[variables('v_tags')]"
          },
          "p_vnetPeeringsCompute": {
            "value": "[parameters('p_vnetPeeringsCompute')]"
          }
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "p_tags": {
              "type": "object",
              "defaultValue": {}
            },
            "p_vnetPeeringsCompute": {
              "type": "array"
            }
          },
          "functions": [],
          "resources": [
            {
              "type": "Microsoft.Network/privateDnsZones",
              "apiVersion": "2020-06-01",
              "name": "compute.bld.local",
              "tags": "[parameters('p_tags')]",
              "location": "Global"
            },
            {
              "copy": {
                "name": "vnl",
                "count": "[length(parameters('p_vnetPeeringsCompute'))]"
              },
              "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
              "apiVersion": "2020-06-01",
              "name": "[format('{0}/{1}', 'compute.bld.local', last(split(parameters('p_vnetPeeringsCompute')[copyIndex()].id, '/')))]",
              "tags": "[parameters('p_tags')]",
              "location": "Global",
              "properties": {
                "virtualNetwork": {
                  "id": "[parameters('p_vnetPeeringsCompute')[copyIndex()].id]"
                },
                "registrationEnabled": false
              },
              "dependsOn": [
                "[resourceId('Microsoft.Network/privateDnsZones', 'compute.bld.local')]"
              ]
            }
          ]
        }
      },
      "dependsOn": [
        "[subscriptionResourceId('Microsoft.Resources/resourceGroups', format('{0}-{1}-compute-rsg', variables('v_shortLocation'), subscription().displayName))]"
      ]
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2020-06-01",
      "name": "privateLink",
      "resourceGroup": "[format('{0}-{1}-link-rsg', variables('v_shortLocation'), subscription().displayName)]",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "mode": "Incremental",
        "parameters": {
          "p_vnetPeeringsLinkFile": {
            "value": "[parameters('p_vnetPeeringsLinkFile')]"
          },
          "p_tags": {
            "value": "[variables('v_tags')]"
          }
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "p_vnetPeeringsLinkFile": {
              "type": "array"
            },
            "p_tags": {
              "type": "object",
              "defaultValue": {}
            }
          },
          "functions": [],
          "resources": [
            {
              "type": "Microsoft.Network/privateDnsZones",
              "apiVersion": "2020-06-01",
              "name": "[format('privatelink.file.{0}', environment().suffixes.storage)]",
              "tags": "[parameters('p_tags')]",
              "location": "Global"
            },
            {
              "copy": {
                "name": "vnl",
                "count": "[length(parameters('p_vnetPeeringsLinkFile'))]"
              },
              "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
              "apiVersion": "2020-06-01",
              "name": "[format('{0}/{1}', format('privatelink.file.{0}', environment().suffixes.storage), last(split(parameters('p_vnetPeeringsLinkFile')[copyIndex()].id, '/')))]",
              "tags": "[parameters('p_tags')]",
              "location": "Global",
              "properties": {
                "virtualNetwork": {
                  "id": "[parameters('p_vnetPeeringsLinkFile')[copyIndex()].id]"
                },
                "registrationEnabled": false
              },
              "dependsOn": [
                "[resourceId('Microsoft.Network/privateDnsZones', format('privatelink.file.{0}', environment().suffixes.storage))]"
              ]
            },
            {
              "type": "Microsoft.Network/privateDnsZones",
              "apiVersion": "2020-06-01",
              "name": "[format('privatelink{0}', environment().suffixes.sqlServerHostname)]",
              "tags": "[parameters('p_tags')]",
              "location": "Global"
            }
          ]
        }
      },
      "dependsOn": [
        "[subscriptionResourceId('Microsoft.Resources/resourceGroups', format('{0}-{1}-link-rsg', variables('v_shortLocation'), subscription().displayName))]"
      ]
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2020-06-01",
      "name": "privateStorage",
      "resourceGroup": "[format('{0}-{1}-storage-rsg', variables('v_shortLocation'), subscription().displayName)]",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "mode": "Incremental",
        "parameters": {
          "p_tags": {
            "value": "[variables('v_tags')]"
          },
          "p_vnetPeeringsStorage": {
            "value": "[parameters('p_vnetPeeringsStorage')]"
          }
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "p_tags": {
              "type": "object",
              "defaultValue": {}
            },
            "p_vnetPeeringsStorage": {
              "type": "array"
            }
          },
          "functions": [],
          "resources": [
            {
              "type": "Microsoft.Network/privateDnsZones",
              "apiVersion": "2020-06-01",
              "name": "storage.bld.local",
              "tags": "[parameters('p_tags')]",
              "location": "Global"
            },
            {
              "copy": {
                "name": "vnl",
                "count": "[length(parameters('p_vnetPeeringsStorage'))]"
              },
              "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
              "apiVersion": "2020-06-01",
              "name": "[format('{0}/{1}', 'storage.bld.local', last(split(parameters('p_vnetPeeringsStorage')[copyIndex()].id, '/')))]",
              "tags": "[parameters('p_tags')]",
              "location": "Global",
              "properties": {
                "virtualNetwork": {
                  "id": "[parameters('p_vnetPeeringsStorage')[copyIndex()].id]"
                },
                "registrationEnabled": false
              },
              "dependsOn": [
                "[resourceId('Microsoft.Network/privateDnsZones', 'storage.bld.local')]"
              ]
            }
          ]
        }
      },
      "dependsOn": [
        "[subscriptionResourceId('Microsoft.Resources/resourceGroups', format('{0}-{1}-storage-rsg', variables('v_shortLocation'), subscription().displayName))]"
      ]
    }
  ]
}

Демо

Это действительно полезно. JQ — это мой запасной вариант, если PowerShell не может делать то, что я хочу, только из-за используемых нами агентов и того, как работают конвейеры. Сначала я буду болтаться, если кто-нибудь предложит исправление для PS.

Beefcake 31.03.2022 11:30
Ответ принят как подходящий

В чистом PowerShell вы можете использовать рекурсивную функцию для очистки любого свойства "metadata" от объектов на любой глубине вложенности.

function StripMetadata {
    param($node)

    if ($node -is [pscustomobject]) {
        foreach ($prop in $node.PSObject.Properties) {
            if ($prop.Name -eq "metadata") {
                $node.PSObject.Properties.Remove($prop.Name)
            } else {
                StripMetadata $prop.Value
            }
        }
    } elseif ($node -is [array]) {
        foreach ($item in $node) {
            StripMetadata $item
        }
    }
}

Обратите внимание, что это изменяет объект на месте, значение результата отсутствует.

$data = $yourJson | ConvertFrom-Json 
StripMetadata $data
$result = $data | ConvertTo-Json -Depth 100 -Compress

$result это (отформатировано):

{
    "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "p_vnetPeeringsCompute": {
            "type": "array"
        },
        "p_vnetPeeringsStorage": {
            "type": "array"
        },
        "p_vnetPeeringsLinkFile": {
            "type": "array"
        },
        "p_tags": {
            "type": "object",
            "defaultValue": {}
        }
    },
    "functions": [],
    "variables": {
        "v_longLocation": "uksouth",
        "v_shortLocation": "uks",
        "v_templateDescription": "Azure Private DNS Template Spec",
        "v_templateDisplayName": "privateDns",
        "v_templateName": "privateDns",
        "v_templateVersion": "2.0.0",
        "v_templateTags": {
            "tsName": "[variables(\u0027v_templateName\u0027)]",
            "tsVersion": "[variables(\u0027v_templateVersion\u0027)]"
        },
        "v_tags": "[union(parameters(\u0027p_tags\u0027), variables(\u0027v_templateTags\u0027))]"
    },
    "resources": [{
        "type": "Microsoft.Resources/resourceGroups",
        "apiVersion": "2021-01-01",
        "name": "[format(\u0027{0}-{1}-compute-rsg\u0027, variables(\u0027v_shortLocation\u0027), subscription().displayName)]",
        "location": "[variables(\u0027v_longLocation\u0027)]",
        "tags": "[variables(\u0027v_tags\u0027)]"
    }, {
        "type": "Microsoft.Resources/resourceGroups",
        "apiVersion": "2021-01-01",
        "name": "[format(\u0027{0}-{1}-link-rsg\u0027, variables(\u0027v_shortLocation\u0027), subscription().displayName)]",
        "location": "[variables(\u0027v_longLocation\u0027)]",
        "tags": "[variables(\u0027v_tags\u0027)]"
    }, {
        "type": "Microsoft.Resources/resourceGroups",
        "apiVersion": "2021-01-01",
        "name": "[format(\u0027{0}-{1}-storage-rsg\u0027, variables(\u0027v_shortLocation\u0027), subscription().displayName)]",
        "location": "[variables(\u0027v_longLocation\u0027)]",
        "tags": "[variables(\u0027v_tags\u0027)]"
    }, {
        "type": "Microsoft.Resources/deployments",
        "apiVersion": "2020-06-01",
        "name": "privateCompute",
        "resourceGroup": "[format(\u0027{0}-{1}-compute-rsg\u0027, variables(\u0027v_shortLocation\u0027), subscription().displayName)]",
        "properties": {
            "expressionEvaluationOptions": {
                "scope": "inner"
            },
            "mode": "Incremental",
            "parameters": {
                "p_tags": {
                    "value": "[variables(\u0027v_tags\u0027)]"
                },
                "p_vnetPeeringsCompute": {
                    "value": "[parameters(\u0027p_vnetPeeringsCompute\u0027)]"
                }
            },
            "template": {
                "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
                "contentVersion": "1.0.0.0",
                "parameters": {
                    "p_tags": {
                        "type": "object",
                        "defaultValue": {}
                    },
                    "p_vnetPeeringsCompute": {
                        "type": "array"
                    }
                },
                "functions": [],
                "resources": [{
                    "type": "Microsoft.Network/privateDnsZones",
                    "apiVersion": "2020-06-01",
                    "name": "compute.bld.local",
                    "tags": "[parameters(\u0027p_tags\u0027)]",
                    "location": "Global"
                }, {
                    "copy": {
                        "name": "vnl",
                        "count": "[length(parameters(\u0027p_vnetPeeringsCompute\u0027))]"
                    },
                    "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
                    "apiVersion": "2020-06-01",
                    "name": "[format(\u0027{0}/{1}\u0027, \u0027compute.bld.local\u0027, last(split(parameters(\u0027p_vnetPeeringsCompute\u0027)[copyIndex()].id, \u0027/\u0027)))]",
                    "tags": "[parameters(\u0027p_tags\u0027)]",
                    "location": "Global",
                    "properties": {
                        "virtualNetwork": {
                            "id": "[parameters(\u0027p_vnetPeeringsCompute\u0027)[copyIndex()].id]"
                        },
                        "registrationEnabled": false
                    },
                    "dependsOn": ["[resourceId(\u0027Microsoft.Network/privateDnsZones\u0027, \u0027compute.bld.local\u0027)]"]
                }]
            }
        },
        "dependsOn": ["[subscriptionResourceId(\u0027Microsoft.Resources/resourceGroups\u0027, format(\u0027{0}-{1}-compute-rsg\u0027, variables(\u0027v_shortLocation\u0027), subscription().displayName))]"]
    }, {
        "type": "Microsoft.Resources/deployments",
        "apiVersion": "2020-06-01",
        "name": "privateLink",
        "resourceGroup": "[format(\u0027{0}-{1}-link-rsg\u0027, variables(\u0027v_shortLocation\u0027), subscription().displayName)]",
        "properties": {
            "expressionEvaluationOptions": {
                "scope": "inner"
            },
            "mode": "Incremental",
            "parameters": {
                "p_vnetPeeringsLinkFile": {
                    "value": "[parameters(\u0027p_vnetPeeringsLinkFile\u0027)]"
                },
                "p_tags": {
                    "value": "[variables(\u0027v_tags\u0027)]"
                }
            },
            "template": {
                "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
                "contentVersion": "1.0.0.0",
                "parameters": {
                    "p_vnetPeeringsLinkFile": {
                        "type": "array"
                    },
                    "p_tags": {
                        "type": "object",
                        "defaultValue": {}
                    }
                },
                "functions": [],
                "resources": [{
                    "type": "Microsoft.Network/privateDnsZones",
                    "apiVersion": "2020-06-01",
                    "name": "[format(\u0027privatelink.file.{0}\u0027, environment().suffixes.storage)]",
                    "tags": "[parameters(\u0027p_tags\u0027)]",
                    "location": "Global"
                }, {
                    "copy": {
                        "name": "vnl",
                        "count": "[length(parameters(\u0027p_vnetPeeringsLinkFile\u0027))]"
                    },
                    "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
                    "apiVersion": "2020-06-01",
                    "name": "[format(\u0027{0}/{1}\u0027, format(\u0027privatelink.file.{0}\u0027, environment().suffixes.storage), last(split(parameters(\u0027p_vnetPeeringsLinkFile\u0027)[copyIndex()].id, \u0027/\u0027)))]",
                    "tags": "[parameters(\u0027p_tags\u0027)]",
                    "location": "Global",
                    "properties": {
                        "virtualNetwork": {
                            "id": "[parameters(\u0027p_vnetPeeringsLinkFile\u0027)[copyIndex()].id]"
                        },
                        "registrationEnabled": false
                    },
                    "dependsOn": ["[resourceId(\u0027Microsoft.Network/privateDnsZones\u0027, format(\u0027privatelink.file.{0}\u0027, environment().suffixes.storage))]"]
                }, {
                    "type": "Microsoft.Network/privateDnsZones",
                    "apiVersion": "2020-06-01",
                    "name": "[format(\u0027privatelink{0}\u0027, environment().suffixes.sqlServerHostname)]",
                    "tags": "[parameters(\u0027p_tags\u0027)]",
                    "location": "Global"
                }]
            }
        },
        "dependsOn": ["[subscriptionResourceId(\u0027Microsoft.Resources/resourceGroups\u0027, format(\u0027{0}-{1}-link-rsg\u0027, variables(\u0027v_shortLocation\u0027), subscription().displayName))]"]
    }, {
        "type": "Microsoft.Resources/deployments",
        "apiVersion": "2020-06-01",
        "name": "privateStorage",
        "resourceGroup": "[format(\u0027{0}-{1}-storage-rsg\u0027, variables(\u0027v_shortLocation\u0027), subscription().displayName)]",
        "properties": {
            "expressionEvaluationOptions": {
                "scope": "inner"
            },
            "mode": "Incremental",
            "parameters": {
                "p_tags": {
                    "value": "[variables(\u0027v_tags\u0027)]"
                },
                "p_vnetPeeringsStorage": {
                    "value": "[parameters(\u0027p_vnetPeeringsStorage\u0027)]"
                }
            },
            "template": {
                "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
                "contentVersion": "1.0.0.0",
                "parameters": {
                    "p_tags": {
                        "type": "object",
                        "defaultValue": {}
                    },
                    "p_vnetPeeringsStorage": {
                        "type": "array"
                    }
                },
                "functions": [],
                "resources": [{
                    "type": "Microsoft.Network/privateDnsZones",
                    "apiVersion": "2020-06-01",
                    "name": "storage.bld.local",
                    "tags": "[parameters(\u0027p_tags\u0027)]",
                    "location": "Global"
                }, {
                    "copy": {
                        "name": "vnl",
                        "count": "[length(parameters(\u0027p_vnetPeeringsStorage\u0027))]"
                    },
                    "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
                    "apiVersion": "2020-06-01",
                    "name": "[format(\u0027{0}/{1}\u0027, \u0027storage.bld.local\u0027, last(split(parameters(\u0027p_vnetPeeringsStorage\u0027)[copyIndex()].id, \u0027/\u0027)))]",
                    "tags": "[parameters(\u0027p_tags\u0027)]",
                    "location": "Global",
                    "properties": {
                        "virtualNetwork": {
                            "id": "[parameters(\u0027p_vnetPeeringsStorage\u0027)[copyIndex()].id]"
                        },
                        "registrationEnabled": false
                    },
                    "dependsOn": ["[resourceId(\u0027Microsoft.Network/privateDnsZones\u0027, \u0027storage.bld.local\u0027)]"]
                }]
            }
        },
        "dependsOn": ["[subscriptionResourceId(\u0027Microsoft.Resources/resourceGroups\u0027, format(\u0027{0}-{1}-storage-rsg\u0027, variables(\u0027v_shortLocation\u0027), subscription().displayName))]"]
    }]
}

Это именно то, что я ищу. Магия, спасибо. Хотя оба решения — это то, что я ищу, я предпочитаю PowerShell для того, что я делаю.

Beefcake 31.03.2022 11:54

@Beefcake, вероятно, работает немного лучше, чем запуск дополнительного процесса для этого, и у него нет внешней зависимости, что приятно.

Tomalak 31.03.2022 12:10

Другие вопросы по теме