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.