Merging ARM Templates using PowerShell

For a project I’m working on we have a massive ARM template and I had to add some stuff, deployment scripts, to it. While I still have enough love for ARM templates to work with it, creating & deploying big deployment scripts with isn’t a great experience.

However, with Bicep I can create (and debug) the script in a proper PowerShell file and load it in the Bicep template using the loadTextContent function. After compiling (az bicep build) the template it will output a nice ARM template for me with the PowerShell file contents inside.

The downside?
Now I’m stuck with 2 ARM templates, and while manual merges are possible I think we all know that’s not something to strive for. What do you do when there’s something on your local machine which needs automation? Right! Reach out to PowerShell to do the automation for you.

Because ARM Templates are JSON (sort of) we can use the built-in functions ConvertFrom-Json and ConvertTo-Json to read & write documents, so that’s what I did.
There’s also this great module called Join-Object by iRon7 which is able to:

Combines two object lists based on a related property between them.

This module has several join options, like InnerJoin, OuterJoin, Merge, and many more. So that’s everything I need for what I want to accomplish, merging 2 ARM templates with eachother.

What we need to do is the following:

  • Merge the parameters object
  • Merge the variables object
  • Add the resources from the new template to the main template
  • Merge the output object

What I came up with is the following script.

Import-Module -Name JoinModule # https://github.com/iRon7/Join-Object/blob/master/README.md

$bicepFileToCompile = "./my-bicep-file-containing-new-resources.bicep"
$compiledArmTemplateWithNewResources = "./my-compiled-arm-template-with-new-resources.json"
$mainArmTemplate = "../main-template.json"

az bicep build --file $bicepFileToCompile --outfile $compiledArmTemplateWithNewResources

$armTemplateObjectWithNewResources = Get-Content -Raw -Path $compiledArmTemplateWithNewResources | ConvertFrom-Json
$mainArmTemplateObject = Get-Content -Raw -Path $mainArmTemplate | ConvertFrom-Json

$mergedArmTemplateParametersObject = $mainArmTemplateObject.parameters | Merge $armTemplateObjectWithNewResources.parameters
$mergedArmTemplateVariablesObject = $mainArmTemplateObject.variables | Merge $armTemplateObjectWithNewResources.variables
$mainResourcesWithoutResourcesWithSpecificPrefix = $mainArmTemplateObject.resources | Where-Object { $_.name -notlike "*prefixOfNewResources*" }
$mergedArmTemplateResourcesObject = $mainResourcesWithoutResourcesWithSpecificPrefix + $armTemplateObjectWithNewResources.resources
$mergedArmTemplateOutputObject = $mainArmTemplateObject.outputs | Merge $armTemplateObjectWithNewResources.outputs

$mainArmTemplateObject.parameters = $mergedArmTemplateParametersObject
$mainArmTemplateObject.variables = $mergedArmTemplateVariablesObject
$mainArmTemplateObject.resources = $mergedArmTemplateResourcesObject
$mainArmTemplateObject.outputs = $mergedArmTemplateOutputObject

$mainArmTemplateObject | ConvertTo-Json -Depth 100 | Out-File $mainArmTemplate

I’m merging the objects (parameters, variables, and output) in the above script and adding the new resources to the collection of existing resources.
One thing to note is the exclusion of resources which have a name like *prefixOfNewResources*. This is because I’m prefixing the name of the resources in the Bicep file with this to make the merging easier. You can probably come up with more advanced solutions, but this is good enough for my purposes.

The above script has been used a couple of times now and it works quite well. An added benefit is the outputted JSON will be nicely formatted by PowerShell so everything is indented correct.


Share