Previous Post in Series: Part 1: ARM Templates – A Walkthrough
Welcome back folks. In part 1 of the series we prepared the accounts and tools we’ll need going forward, so we can just dive right into it now.
When I initially started working with ARM templates, I wanted a way to break things up into small munchable chunks that I could easily digest, this way I could remember what I learned and was at the same time creating a framework for learning that I could pass on to others within my team. The upshot of this is that I can also blog about it here 🙂
Hopefully the steps I’ve taken to learn this will also help some of you…that’s the goal anyway.
OK, let’s get to it.
Download ARM Templates
First we’ll want to grab a hold of the template we’ll be working with for the rest of this guide, you can download it HERE
- Click “Clone or download” and select “Download Zip”

- Now unzip the archive to a location of your choosing, something easy to remember 🙂

From here on out, the instructions I’ll be laying out are for using Visual Studio Code (VSC).
- Launch VSC and Click “File”, “Open Folder”
- Browse the directory highlighted in the screenshot above and click “Open”
This will open the whole template at once, which is good as we’ll be working on a few of the files within. Your editor should look something like this:

For the time being, we’re interested in the file named “azuredeploy.json”, so click on it and let’s get into the actual code.
So What Does This Template Do?
Actually, I’m gonna pull a Columbo here and say “One more thing” before we get into the code. We should probably go over what the template actually does first right? So here it is:
- Deploys between 1 and 4 Windows Server 2016 VMs with the IIS role installed
- The user can choose between 5 available sizes for these “web servers”
- Creates a single Windows Server 2016 VM running SQL Server 2016 SP1 Standard
- This server has an additional 50GB data disk
- The user can choose between 4 available sizes for this SQL server
- Creates a Network Security Group for the Frontend subnet with:
- Port 3389 (RDP) enabled inbound from the internet
- Port 80 (http) enabled inbound from the internet
- Creates a Network Security Group for the Backend subnet with:
- Port 1433 allowed inbound from the Frontend subnet
- Port 3389 (RDP) allowed inbound from the internet
- A rule blocking all traffic from the Frontend to Backend subnet *
- A rule blocking all traffic from the internet
- Creates a Virtual Network with a /16 address prefix with a /24 Frontend and Backend subnet carved out
- Creates a Storage Account, the user can choose between:
- Standard (HDD) Locally Redundant (Resilient within an Azure datacenter, 3 copies kept)
- Premium (SSD) Locally Redundant
- Creates a Public IP Address for the SQL Server – mainly for testing purposes
- Create a Network Adapter for the SQL Server
- Creates an Availability Set for above Web Servers
- Creates a Public IP address to be used by the web server Load Balancer
- Creates a Load Balancer for the Web Server VMs with:
- Inbound NAT rules allowing RDP from the internet
- A TCP probe targeting port 80 (http)
- Creates a Network Adapter for the Web Server VMs
- Installs the PowerShell DSC extension on the Web Server VMs to install and configure the IIS role
*NOTE: Allow rules will always take priority over denies
Template Parameters and Variables
Parameters
If you’ve ever done any coding before, you’ll have heard of parameters and variables. Within the context of ARM templates, “Parameters” are values you’ll be asked to enter at the point of template deployment. You have quite a bit of control over these parameters, the following table lists the configurable options:
Parameter Element | Description |
---|---|
parameterName | As expected, this is the name you give your parameter |
type | This allows you to set the parameter type, there is a list below this table showing accepted values |
defaultValue | This allows you so set a default value for the parameter that will be used if the user leaves it blank during deployment |
allowedValues | This lets you scope down the accepted values for your parameter |
minValue | Allows you to set a minimum value for integer typed parameters |
maxValue | As above but sets a maximum |
minLength | Allows you to set a minimum character length for string, secureString and array typed parameters |
maxLength | As above but sets a maximum |
description | Allows you to set a description for your parameter, this description is exposed to the user via the portal during deployment, so make it good. |
Here’s an example from our template of a parameter using some of the elements listed above

Variables
Variables are values that are configured within the template and can be either hard-coded, I.e. a specific value or can be the result of an expression. While we’re on the subject of expressions, this is a value placed between [ and ] and who’s result is evaluated then the template is deployed.
EXAMPLE:
“frontendNSGName”: “[concat(parameters(‘customerPrefixID’), ‘FrontendNSG’)]”

So when the template is deployed, the expression is evaluated and the value of the frontendNSGName variable becomes: the value of the ‘customerPrefixID’ parameter with ‘FrontendNSG’ tacked on the end.
I’ve put together a spreadsheet mapping out our example templates parameters and variables. This provides a little more information on their purpose within the template I.e. what resource they relate to etc.
Resources
Resources are snippets of code within the template that deploy the actual resources that make up your solution. This is where things can get a little trickier as you have to be aware of the types of resources you are deploying, what values are required for that resource and what dependencies it may have on other resources within the template.
The following website is a great resource to assist you when authoring templates and includes:
- Most recent API version for the resource
- A JSON code block for the template
- A list and description of the property values available for the resource
- A link to some related quick-start templates using the specific resource
https://docs.microsoft.com/en-us/azure/templates/
You can also jump straight to a resource reference is you know its name, using the following URL format:
https://docs.microsoft.com/azure/templates/{provider-namespace}/{resource-type}
Example:
https://docs.microsoft.com/azure/templates/microsoft.compute/virtualmachines
Let’s have a look at one of the resources deployed in our template to see some of this in context:

Notice “dependsOn:” in the above screenshot, this gives us some control over the resource deployment order. In the context of our template, we’re creating a Network Security Group for our Frontend and Backend subnets with a couple of configured rules in each. As the subnets in our Virtual Network rely on the Network Security Groups for their creation, the Virtual Network needs to have these listed as dependencies (see above).
While we’re on the subject of dependencies, I’ve created a diagram that maps out our template and lists all resources in order of deployment. The main takeaway though is that it shows:
- Resource dependencies
- Resource dependents
- Resources that are both dependencies and dependents

So that’s the “azuredeploy.json” file pretty much covered, but what do the other files in the directory do?
Name | Purpose |
---|---|
azuredeploy.json | Most of the work above concerned this file, this is the main deployment template file. |
azuredeploy.parameters.json | You can use this file to store the parameters used in your template instead of specifying them in "azuredeploy.json" if that's your preference. We don't really make use of it in this template though. |
metadata.json | Contains data about the template for its use and publication. We'll make use of this when we upload it to our GitHub account later |
README.md | This file should describe the template contents and what it does. We'll make heavy use of this file when we upload to GitHub later |
\scripts | This directory contains a zip archive named "WebServerConfig.ps1.zip", which contains a PowerShell script named "WebServerConfig.ps1". This script is used by PowerShell DSC to…you guessed it, configure IIS on our Web Servers. |
\images | This directory contains images referenced in our README.md which GitHub can parse and display on our template overview page…but more on this later. |
The Scripts Directory
In the above table I provided a little information on what’s stored in the “scripts” folder of our template directory but how does our template actually make use of these artefacts? The first thing we need is two parameters placed in the template, these are:

As you can see, we’ve made use of the “defaultValue” property to specify the URI for our template on GitHub. The SAS token will be auto generated at the point of deployment.
We’ve also created two variables in our template to provide both the URL to our script archive, including the SAS Token to access it and one calling the WebServerConfig DSC function within our PowerShell script.

These variables are called within the “Properties” section of our Extensions resource:

Upload Our Template to GitHub
In Part 1 we created a GitHub account with a public repository, now we’re going to upload our template to that repo. This part of the guide is to illustrate how GitHub understands ARM templates and give a little more context around the Images directory and the README.md file.
Let’s get to it.
- Log into the GitHub account you created earlier
- The repository you created earlier should be listed on the right, click it

- Click on “Upload files”

- Browse to where you saved the template we downloaded earlier (the IIS-4VM-SQL-1VM folder) and drag it to window shown below

- Now add a short note to your “Commit” and click “Commit changes”

You’ll now be placed back in the top level of your repository and you should see the folder you just uploaded, click on it.

We’re now looking at our template page within the repo, it seems we’ve not only got the ability to deploy our template straight to Azure from here but a boatload of information and diagrams about the template…where is that coming from?
That’s where our README.md file comes into play. GitHub can parse data we add to that file and can lay it out nicely etc. depending on how we format it. Let’s look into that in a little more detail, I’ll break it down into sections:
Template Title and Deploy to Azure Buttons

The following text in the README.md file is responsible for everything you see in the image above and is mainly just HTML.

The URLs would need to be changed to reference your specific template “azuredeploy.json” file. You can get this URL by clicking on the file in your GitHub repo and clicking the button “Raw”


When formatting headings in the README file, use a single # for Heading 1 and a double ## for Heading 2, you can see the difference when looking at the headings “IaaS IIS and SQL on Windows Server 2016” and “Resources”.
You can also look at a visual representation of your ARM template by clicking on the “Visualize” button. This lets you see how your resources are mapped together and what names some of those resources will end up with.
Images
I mentioned earlier, we have a folder named “images” in our template folder, we can reference these images in our README file to be displayed on our template overview page by adding HTML links to them.


Not much more to say on this part, it’s nice though 🙂
PowerShell Deployment
GitHub can also render your PowerShell code on this page (among other languages), to do this add ““`PowerShell” (without quotes) before your code and ““`” (again, without quotes) at the end of your code.


That’s it for Part 2, in Part 3 we’ll go over 3 of the most commonly used ARM template deployment methods, see you then.