
close
close
Chance to win $250 in Petri 2023 Audience Survey
In today’s Ask the Admin, I’ll show you how to deploy a VM in Azure using the new Resource Manager deployment model and PowerShell.
If you think back to my article Deploy VMs Using Azure Resource Manager on the Petri IT Knowledgebase, you’ll recall that I showed you how to deploy a VM in Azure using the new management portal, which supports a deployment method called Resource Manager.
While Azure Resource Manager (ARM) brings a new level of flexibility to Azure over the classic deployment method, if you followed through the instructions in the link above, you’ll have realized that the process is more complex than before. In fact, ARM reminds me somewhat of deploying VMs in the Amazon cloud, which is more complicated than deploying Azure VMs in classic mode. To get a better understanding of Resource Manager and how it differs from the classic deployment method, see Aidan Finn’s piece A Tale of Two Azures on Petri.
Logging in and setting a subscription to use with Azure Resource Manager (ARM). (Image Credit: Russell Smith)
So it should come as no surprise that deploying ARM-based VMs using PowerShell is also considerably more complicated than was previously the case. Each resource must be provisioned manually, unlike using the classic-mode cmdlets, where much of the heavy lifting was automated behind the scenes.
The following script deploys a basic A0 VM in Azure using standard storage, a dynamic public IP address and friendly DNS name. A storage account is also created. The script creates a Resource Group (RG), Virtual Network (VNET), and subnet if resources with the names specified in the script variables are not found in the Azure subscription.
Note that before you can work with ARM in PowerShell, you’ll need to install Microsoft Azure PowerShell 1.0 or later. See Microsoft Releases Azure PowerShell 1.0 on Petri for more details.
First the script needs to log in to ARM, and while most readers will only have one Azure subscription associated with their Microsoft Account, the script selects the first [0] sub listed by the Select-AzureRmSubscription cmdlet.
Login-AzureRmAccount $subs = Get-AzureRmSubscription Select-AzureRmSubscription -TenantId $subs[0].TenantId -SubscriptionId $subs[0].SubscriptionId
Next I set variables required throughout the rest of the script, such as the RG name ($rgName), location ($location), VM name, virtual network name ($vnetName), amongst others. The username and password for the VM are converted to a secure string and system object. The $vmName variable should be given in lowercase with no special characters because I reuse it for the storage account name, which has these restrictions placed upon it.
$rgName ='ContosoSRVs' $location = 'North Europe' $vnetName = 'CONTOSO' $ipAddress = '10.0.0.7' $Range = '10.0.0.0/16' $subNetRange = '10.0.0.0/24' $subnetname = 'Subnet-1' $vmSize = 'Basic_A0' $osSKU = '2012-R2-Datacenter' $vmName = 'contososrv1' $storaccName = $vmName + 'stor' # Usernames and passwords $username = 'srvadmin' $password = 'PassW0rd!' $passwordsec = convertto-securestring $password -asplaintext -force $creds = New-Object System.Management.Automation.PSCredential($username, $passwordsec)
Now let’s create a new RG, if one with the name given in $rgName doesn’t already exist in the Azure subscription:
try { Get-AzureRmResourceGroup -Name $rgName -Location $location -ErrorAction Stop Write-Host 'RG already exists... skipping' -foregroundcolor yellow -backgroundcolor red } catch { New-AzureRmResourceGroup -Name $rgName -Location $location }
Create a new Resource Group using PowerShell ARM (Image Credit: Russell Smith)
In a similar manner, a new storage account will be created. The script is aborted if the storage account name isn’t globally unique, i.e. it must not exist in any Azure subscription.
if (Test-AzureName -Storage $storaccName) { Throw 'Storage account already name exists... aborting' } else { New-AzureRmStorageAccount -Name $storaccName -ResourceGroupName $rgName –Type 'Standard_LRS' -Location $location }
Now we need to set up a VHD file in Azure storage:
$storacct = Get-AzureRmStorageAccount -ResourceGroupName $rgName –StorageAccountName $storaccName $disknameOS = $vmname + 'diskOS' $vhduri = $storacct.PrimaryEndpoints.Blob.OriginalString + 'vhds/${disknameOS}.vhd'
The script then determines the latest available image for Windows Server 2012 R2 Datacenter:
$images = Get-AzureRmVMImage -Location $location -PublisherName 'MicrosoftWindowsServer' -Offer 'WindowsServer' -Skus $osSKU | Sort-Object -Descending -Property PublishedDate
Next up is networking, and here I create a public IP address resource with friendly DNS name, and a subnet object so that a virtual network can be created if one doesn’t already exist with the given name:
$pip = New-AzureRmPublicIpAddress -Name "${vmname}_nic1" -ResourceGroupName $rgName -DomainNameLabel $vmName -Location $location -AllocationMethod Dynamic $subnet1 = New-AzureRmVirtualNetworkSubnetConfig -Name $subnetname -AddressPrefix $subNetRange try { $vnet = Get-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $rgName -ErrorAction Stop Write-Host 'VNET already exists... skipping' -foregroundcolor yellow -backgroundcolor red } catch { $vnet = New-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $rgName -Location $location -AddressPrefix $Range -Subnet $subnet1 } $subnet = Get-AzureRmVirtualNetworkSubnetConfig -VirtualNetwork $vnet
Here the VM is assigned a Network Interface Card (NIC) resource:
$nic = New-AzureRmNetworkInterface -Name "${vmname}_nic1" -Location $location -ResourceGroupName $rgName -SubnetId $vnet.Subnets[0].Id -PublicIpAddressId $pip.Id
Now we’re ready to provision the VM, using the New-AzureRmVMConfig, Add-AzureRmVMNetworkInterface, Set-AzureRmVMOperatingSystem, Set-AzureRmVMSourceImage, Set-AzureRmVMOSDisk to define the VM’s properties, and New-AzureRmVM to perform the actual deployment job. The New-AzureRmVM cmdlet can take a long time to complete.
VM properties in Azure RM (Image Credit: Russell Smith)
$newVM = New-AzureRmVMConfig -Name $vmName -VMSize $vmSize $newVM = Add-AzureRmVMNetworkInterface -VM $newVM -Id $nic.Id Set-AzureRmVMOperatingSystem -Windows -VM $newVM -ProvisionVMAgent -EnableAutoUpdate -Credential $creds -ComputerName $vmname Set-AzureRmVMSourceImage -VM $newVM -PublisherName $images[0].PublisherName -Offer $images[0].Offer -Skus $images[0].Skus -Version $images[0].Version Set-AzureRmVMOSDisk -VM $newVM -Name $disknameOS -VhdUri $vhduri -Caching ReadWrite -CreateOption fromImage New-AzureRmVM -ResourceGroupName $rgName -Location $location -VM $newVM -Verbose
Finally, the script outputs to the console the URL for connecting to the new VM using RDP:
$rdpVM = get-azurermvm -ResourceGroupName $rgName -Name $vmName $rdpString = $vmName + '.' + $rdpVM.Location + '.cloudapp.azure.com:3389' Write-Host 'Connect to the VM using the URL below:' -foregroundcolor yellow -backgroundcolor red Write-Host $rdpString
RDP connection string to the new VM (Image Credit: Russell Smith)
You can now use this script to quickly deploy VMs, and associated resources, in Azure without having to wade through the wizards in the web management portal. Keep a look out on Petri for some forthcoming articles on how to deploy domain controllers and member servers using PowerShell ARM.
More in Microsoft Azure
Microsoft Introduces Fully-Managed Azure Load Testing Service for Developers
Feb 2, 2023 | Rabia Noureen
Azure Native New Relic Service Provides Full Stack Observability To Boost Digital Transformation
Jan 25, 2023 | Rabia Noureen
Microsoft to Roll Out EU Data Boundary Plan for Cloud Services on January 1
Dec 15, 2022 | Rabia Noureen
Most popular on petri