Although there are plenty of post around using Pester to validate/test ARM templates, most of their approach is around validating the ARM Template contains the components you expect or deployed components are the ones you expect too. However, to me these aren’t the most common frustrations or time lost you get out of writting ARM Templates and those are as important as these tests too and the sooner you finding, the less troubleshooting you’ll need to do. Let alone more complex scenarios where you either do copy loop within the ARM Template or use linked templates for increasing reusability.

Real-world ARM Template Authoring

When I need to write an ARM Template, I always start out of the Azure Portal, using the UI, filling the fields with easy-to-remember values so at the last step, instead of deploying, I download the automation script. (yeah, I know you can type from scratch by using the ARM Reference but the other way feels easier) What happens next is some parameters would became variables, new parameters or variables may appear, ARM functions would replace inefficiencies in the template or to enforce corporate standards.

and the gotcha’s are…

Well, it’s always to expect to:

  • Have forgotten some parameters that became variables or were renamed.
    "parameters": {
    "computerName": {
    "type": "string"
    "variables": {
    "networkInterfaceName": "[concat(parameters('virtualMachineName'),'_NIC01')]"
  • Have forgotten some variables that became parameters or were renamed.
    "parameters": {
    "virtualNetworkName": {
    "type": "string"
    "subnetName": {
    "type": "string"
  • Have a missing parenthesis or square brackets (this is a particularly painful one since depending on the location of the type, the error you get might be really misleading)
    "resources": [
    "type": "Microsoft.KeyVault/vaults",
    "name": "[concat(parameters('resourcesPrefix'),'_Vault']

and if we talk about reusability…

Generally, when you are in company, Azure Resources aren’t just the resource but a bunch of extra configurations which respond to increase (or apply) security; enabling monitoring and diagnostics; enabling log retention; enabling restore or etc. In this scenario, it’s a good practice to create ARM Templates for each component (containing the base resource + secret sauce) and creating a main ARM template for “orchestrating”/combining the others.

we have more gotcha’s (of course)

in this stage, we can get issues such as:

  • Forgot to copy the linked ARM Template into a particular folder or have a type on its filename
  • Not passing all the required parameters to the linked template or assuming parameter names that don’t match

The final result

Frustration. Basically you just realize of these things as you deploy to Azure and miserably fail. You end up wasting a hugemongo amount of time just getting things right and not even deploying a single component yet. Or all these might happen during a Build and Release process.

How can we identify issue earlier?

Simple answer: having tests looking for this scenarios and being a Powershell guy, I chose writting those tests in Pester. You can find the full script in my GitHub repo: azureDeploy.tests.ps1

How does it work?

The script will test any Azure ARM template found in the location where it’s being called from and their linked templates as well (it assumes linked templates to be in a folder, at the root, called ‘linked’).

A “Describe” will be generated per json file and a “Context” per each test group. These are the different test groups (or Context) an ARM Template is evaluated against:

Context: “JSON Structure”

Evaluates basic Azure ARM template structure such as being less than 1 MB, having up to 256 parameters and having the proper regions. “Parameters” and “Resources” are considered mandantory sections while “Variables” and “Outputs” are optional ones.


Context: “Referenced Parameters”

It reads through the template for any parameters(‘[Name]’) and verifies if it’s defined in the parameters section.


Context: “Referenced Variables”

It reads through the template for any variables(‘[Name]’) and check if it’s defined in the variables section.


Context “Missing opening or closing square brackets”

Just as it states, it reads line by line searching for lines with missing square brackets. If there aren’t any, it will not just generate an “It” clause. Otherwise, it will generate one “It” clause per missing square brackets including the line where it’s missing.

Context “Missing opening or closing parenthesis”

Same as “Missing opening or closing square brackets” context but for parenthesis.


Context “Azure API Validation”

If Powershell session is logged into Azure, it makes use of Test-AzureRmResourceGroupDeployment to validate the template. Running this cmdlet requires two thing:

  1. Target resource group must exist
  2. All parameters must be passed

To tackle this, the scripts will attemp to use a resource group called “PesterRG”, if it exists, it will be used (no changes will be made to it). Otherwise, it will create the Resource Group, run the cmdlet and then delete it. In order to be able to run the cmdlet, it will go through all the template parameters and provide dummy data for each one of them (that don’t have a “defaultValue”). Make sure linked templates are uploaded to the Uri their specify, otherwise it will fail.


Context “Nested Template: [template name].json”

If the template contains any resource of the type “Microsoft.Resources/deployments”, it will validate the linked template exists in “linked” folder and its parameters without defaultValue are specified in this template.