How to create an Azure Virtual Machine with ARM Template (2024)

A year ago in this post we created an Azure Virtual Machine using PowerShell instead of using the Azure Portal. This is fairly simple and allows a level of automation. But ARM Templates are simpler and in my opinion easier to source control.

Today lets create the same Virtual Machine, but using ARM this time.

First, fire up a PowerShell console and login to your subscription:

Login-AzureRmAccount
1. Create your ARM Template file

Fire up your favourite editor, Visual Studio Code or Visual Studio itself are my two choices.

Create a new JSON file and name it new-vm.json

Copy and paste the following structure into the new file. This is the beginning of our ARM Template.

{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { }, "variables": { }, "resources": [ ], "outputs": { }}
2. Create PowerShell Script that will run our ARM Template

This of course can be done just in the PowerShell command line, but it’s much faster and more repeatable to create the script file and be able to run it multiple times without having to type these things out.

Create a new file called deploy-new-vm.ps1

3. Create a Resource Group

Just like last time we need to create a Resource Group, this is the logical place to group all the elements that we’re going to create. This needs to be done in PowerShell, so let’s add the following to our new deploy-new-vm.ps1 file.

We also need to select the subscription that we want to put this new Resource Group into, you can get a list of all your subscriptions by using the Get-AzureRmSubscription command, choose which you want and copy the Id and enter into the $subscriptionId below

$subscriptionId = "<YOUR_SUBSCRIPTION_ID>"Select-AzureRmSubscription -SubscriptionId $subscriptionId$resourceGroup = "test-infra"$location = "North Europe"New-AzureRmResourceGroup -Name $resourceGroup -Location $location
4. Create storage account

Finally something that we can add to our new ARM Template.

First, add the following parameter to the “parameters” part of the template

"parameters": { "storageName": { "type": "string", "defaultValue": "teststorage", "metadata": { "description": "Name for our storage account" } } }

Now add a new resource, which is our storage account.

 "resources": [ { "name": "[concat(parameters('storageName'), uniqueString(resourceGroup().id))]", "type": "Microsoft.Storage/storageAccounts", "location": "[resourceGroup().location]", "apiVersion": "2015-06-15", "properties": { "accountType": "Standard_LRS" } } ]

This is the same as our storage we created in the previous post.

We take the storageName which is a parameter and we add a unique string which is generated by uniqueString(resourceGroup().id) this means we can run this multiple times, and also that we won’t clash with anybody else’s storage accounts in the Azure cloud.

The location is defined from where the resourcegroup is located by using [resourceGroup().location]

The storage account type is still the Standard Locally Redundant Storage.

The full file will now look like so:

{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "storageName": { "type": "string", "defaultValue": "teststorage", "metadata": { "description": "Name for our storage account" } } }, "variables": { }, "resources": [ { "name": "[concat(parameters('storageName'), uniqueString(resourceGroup().id))]", "type": "Microsoft.Storage/storageAccounts", "location": "[resourceGroup().location]", "apiVersion": "2015-06-15", "properties": { "accountType": "Standard_LRS" } } ], "outputs": { }}
5. Create Virtual Network

The Virtual Machine needs to live in a Virtual Network, so we create a new Resource in the ARM Template

{ "name": "test-net", "type": "Microsoft.Network/virtualNetworks", "location": "[resourceGroup().location]", "apiVersion": "2015-06-15", "properties": { "addressSpace": { "addressPrefixes": [ "10.0.0.0/16" ] }, "subnets": [ { "name": "frontendSubnet", "properties": { "addressPrefix": "10.0.1.0/24" } } ] } }
6. Setup IP Address and Network Interface

We need to give our new Virtual Machine a Network Interface and an IP address. This can be static, but we’re going to leave it as dynamic as per the last post.

Create a new resource for our Public IP address that we will use to RDP into the VM

 { "apiVersion": "2016-03-30", "type": "Microsoft.Network/publicIPAddresses", "name": "test-publicip", "location": "[resourceGroup().location]", "properties": { "publicIPAllocationMethod": "Dynamic" } }

Lets create a parameter for our VM Name

"vmName": { "type": "string", "defaultValue": "testvm1", "metadata": { "description": "Name for our Virtual Machine" } }

Now let’s create a new resource for our new Network Interface

{ "name": "[concat(parameters('vmName'),'-nic0')]", "type": "Microsoft.Network/networkInterfaces", "location": "[resourceGroup().location]", "apiVersion": "2017-06-01", "properties": { "ipConfigurations": [ { "name": "ipconfig", "properties": { "privateIPAllocationMethod": "Dynamic", "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses','test-publicip')]" }, "subnet": { "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', 'test-net'),'/subnets/','frontendSubnet')]" } } } ] } }

You can see here, we are using the concat keyword to create a name for our Network Interface prefix of the VM Name and then adding -nic0

7. Create our Virtual Machine
{ "name": "[concat(parameters('vmName'))]", "type": "Microsoft.Compute/virtualMachines", "location": "[resourceGroup().location]", "apiVersion": "2017-03-30", "dependsOn": [ "[concat('Microsoft.Network/networkInterfaces/',parameters('vmName'),'-nic0')]" ], "properties": { "hardwareProfile": { "vmSize": "Basic_A1" }, "osProfile": { "computerName": "[parameters('vmName')]", "adminUsername": "YOURUSERNAME", "adminPassword": "YOUR_PASSWORD12345678" }, "storageProfile": { "imageReference": { "publisher": "MicrosoftWindowsServer", "offer": "WindowsServer", "sku": "2012-R2-Datacenter", "version": "latest" }, "osDisk": { "osType": "Windows", "name": "[concat(parameters('vmName'),'-','osdisk')]", "createOption": "FromImage", "caching": "ReadWrite" } }, "networkProfile": { "networkInterfaces": [ { "id": "[concat(resourceId('Microsoft.Network/networkInterfaces',concat(parameters('vmName'))),'-nic0')]" } ] } } }

The dependsOn value in this resource means that it will wait until the provisioning of the specified resource before beginning creating this current resource. You can depend on multiple resources. In this case we are depending on the Network Interface being setup before we continue to create the Virtual Machine.

8. Deploy the ARM Template

Let’s add the deployment of the ARM Template to our deploy-new-vm.ps1 script

New-AzureRmResourceGroupDeployment ` -Name test-infra-deployment ` -ResourceGroupName $resourceGroup ` -TemplateFile new-vm.json ` -Verbose -Force
The full solution

Our final ARM Template json file (new-vm.json) looks like this:

{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "storageName": { "type": "string", "defaultValue": "teststorage", "metadata": { "description": "Name for our storage account" } }, "vmName": { "type": "string", "defaultValue": "testvm1", "metadata": { "description": "Name for our Virtual Machine" } } }, "variables": { }, "resources": [ { "name": "[concat(parameters('storageName'), uniqueString(resourceGroup().id))]", "type": "Microsoft.Storage/storageAccounts", "location": "[resourceGroup().location]", "apiVersion": "2015-06-15", "properties": { "accountType": "Standard_LRS" } }, { "name": "test-net", "type": "Microsoft.Network/virtualNetworks", "location": "[resourceGroup().location]", "apiVersion": "2015-06-15", "properties": { "addressSpace": { "addressPrefixes": [ "10.0.0.0/16" ] }, "subnets": [ { "name": "frontendSubnet", "properties": { "addressPrefix": "10.0.1.0/24" } } ] } }, { "apiVersion": "2016-03-30", "type": "Microsoft.Network/publicIPAddresses", "name": "test-publicip", "location": "[resourceGroup().location]", "properties": { "publicIPAllocationMethod": "Dynamic" } }, { "name": "[concat(parameters('vmName'),'-nic0')]", "type": "Microsoft.Network/networkInterfaces", "location": "[resourceGroup().location]", "apiVersion": "2017-06-01", "properties": { "ipConfigurations": [ { "name": "ipconfig", "properties": { "privateIPAllocationMethod": "Dynamic", "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses','test-publicip')]" }, "subnet": { "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', 'test-net'),'/subnets/','frontendSubnet')]" } } } ] } }, { "name": "[concat(parameters('vmName'))]", "type": "Microsoft.Compute/virtualMachines", "location": "[resourceGroup().location]", "apiVersion": "2017-03-30", "dependsOn": [ "[concat('Microsoft.Network/networkInterfaces/',parameters('vmName'),'-nic0')]" ], "properties": { "hardwareProfile": { "vmSize": "Basic_A1" }, "osProfile": { "computerName": "[parameters('vmName')]", "adminUsername": "YOURUSERNAME", "adminPassword": "Your_PASSWORD12345678" }, "storageProfile": { "imageReference": { "publisher": "MicrosoftWindowsServer", "offer": "WindowsServer", "sku": "2012-R2-Datacenter", "version": "latest" }, "osDisk": { "osType": "Windows", "name": "[concat(parameters('vmName'),'-','osdisk')]", "createOption": "FromImage", "caching": "ReadWrite" } }, "networkProfile": { "networkInterfaces": [ { "id": "[concat(resourceId('Microsoft.Network/networkInterfaces',concat(parameters('vmName'))),'-nic0')]" } ] } } } ], "outputs": { }}

And our Powershell file (deploy-new-vm.ps1):

$subscriptionId = "<YOUR_SUBSCRIPTION_ID>"Select-AzureRmSubscription -SubscriptionId $subscriptionId$resourceGroup = "test-infra"$location = "North Europe"New-AzureRmResourceGroup -Name $resourceGroup -Location $locationNew-AzureRmResourceGroupDeployment ` -Name test-infra-deployment ` -ResourceGroupName $resourceGroup ` -TemplateFile new-vm.json ` -Verbose -Force
Deploy it!

Pull up a PowerShell prompt and make sure you have already run Login-AzureRmAccount, browse to your folder where our two new files are located and run them.

cd c:\dev\Create-VM-with-ARM\.\deploy-new-vm.ps1
Github

Source files available on github

How to create an Azure Virtual Machine with ARM Template (2024)
Top Articles
Small Incremental Improvements Are Small Steps to Huge Change
What is the best time of day to trade XAU USD?
Gamevault Agent
Www.metaquest/Device Code
Health Benefits of Guava
Select The Best Reagents For The Reaction Below.
Imbigswoo
Moe Gangat Age
General Info for Parents
Craigslist Motorcycles Orange County Ca
Mills and Main Street Tour
Sport-News heute – Schweiz & International | aktuell im Ticker
Sonic Fan Games Hq
Puretalkusa.com/Amac
Lehmann's Power Equipment
Ms Rabbit 305
SF bay area cars & trucks "chevrolet 50" - craigslist
11 Ways to Sell a Car on Craigslist - wikiHow
Munis Self Service Brockton
South Bend Weather Underground
Cona Physical Therapy
Wbap Iheart
3 Ways to Format a Computer - wikiHow
Sinai Sdn 2023
Obsidian Guard's Skullsplitter
Napa Autocare Locator
Landing Page Winn Dixie
Haunted Mansion Showtimes Near Cinemark Tinseltown Usa And Imax
Colin Donnell Lpsg
NIST Special Publication (SP) 800-37 Rev. 2 (Withdrawn), Risk Management Framework for Information Systems and Organizations: A System Life Cycle Approach for Security and Privacy
Gabrielle Enright Weight Loss
Rocketpult Infinite Fuel
Empire Visionworks The Crossings Clifton Park Photos
National Insider Threat Awareness Month - 2024 DCSA Conference For Insider Threat Virtual Registration Still Available
301 Priest Dr, KILLEEN, TX 76541 - HAR.com
The Angel Next Door Spoils Me Rotten Gogoanime
Beaufort SC Mugshots
Conan Exiles Armor Flexibility Kit
Thotsbook Com
Television Archive News Search Service
Babykeilani
Chubbs Canton Il
Kjccc Sports
Spreading Unverified Info Crossword Clue
Huntsville Body Rubs
Wood River, IL Homes for Sale & Real Estate
Mmastreams.com
Download Twitter Video (X), Photo, GIF - Twitter Downloader
Ff14 Palebloom Kudzu Cloth
Latest Posts
Article information

Author: Lilliana Bartoletti

Last Updated:

Views: 5852

Rating: 4.2 / 5 (73 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Lilliana Bartoletti

Birthday: 1999-11-18

Address: 58866 Tricia Spurs, North Melvinberg, HI 91346-3774

Phone: +50616620367928

Job: Real-Estate Liaison

Hobby: Graffiti, Astronomy, Handball, Magic, Origami, Fashion, Foreign language learning

Introduction: My name is Lilliana Bartoletti, I am a adventurous, pleasant, shiny, beautiful, handsome, zealous, tasty person who loves writing and wants to share my knowledge and understanding with you.