September 20, 2015

Creating a VM in Azure with ARM and PowerShell

Updated 01/29/2015 Updated to reflect newest (1.0+ PowerShell commands).

Today, I'm going to share something that took me substantially longer to learn than it should: how to create a VM in Azure. You might be thinking, um, Derek, don't you know how to do this already? Well of course I do - just not with the use case I needed. Here are my requirements:

  1. Use Azure Resource Manager - cause the legacy Azure stuff (ASM) is going away soon(ish).
  2. Use an EXISTING already created disk that isn't sysprepped - I'm moving a VM from Classic Azure to ARM Azure to take advantage of things and I don't want to go through deployments.
  3. NOT use a deployment template - these things are great for spinning up large chunks of infrastructure all at once in a repeatable fashion, but they are incredibly hard and unwieldy for the "one off VM" like this one.

First, I needed some PowerShell - so I assume you have the Azure Powershell stuff installed. If not, go here.

Next, open up PowerShell ISE as admin and do an


then get into the right subscription with

select-AzureRMSubscription -subscriptionname "Your Subscription Name Here"

Now you are in the right mode and subscription so hopefully things will land where they need to be. In my instance, I need to use an existing VM from classic land, so before I go creating a VM, I need to have it in an ARM storage account which requires a resource group. So we start there:

new-AzureRMResourceGRoup -name "My Resource Group" -location "centralus"

That's pretty straight forward. There are about 30 billion overloads for that sucker (which means it is way more powerful than that) but I just need a group for now, I can secure it and do other shiny things later.

Now that I have my resource group, I will create the storage account:

new-AzureRMStorageAccount -name "My Storage Account Name" -location "centralus" -resourcegroupname "My Resource Group" -type "Standard_LRS"

Everything above is pretty straight forward except type: that's an enum of what kind of storage you want. Since this is a VM, I don't need anything fancy so I chose 'standard locally redundant storage,' - you could have chosen several other flavors like geo redundant, premium, etc.

Now, I have to get the VM disk from the old classic storage account to the new shiny one. First, and most importantly, make sure the thing is shut down :) Next, fire up the Azure Storage Tools (installed with the PowerShell stuff if you did it right) which is another command prompt. AST lets me copy the VHD from one storage location to another without first downloading it and uploading it - a nice treat. You'll need the storage keys for both the old storage endpoint and the new one you just created. Those can be obtained with PowerShell:

get-azurestorageaccountkey -name "The Name of your Storage Account" -resourcegroupname "The Name of Your Resource Group"

I typically use Key 1. Note - you may be asking yourself - if my old VM is in Classic Mode Azure and Classic Mode Azure doesn't have resource groups, what do I put in there? Answer: it actually does - consult the portal and you will see some "default resource groups" --> these are classic resource groups and you can use the name of that default group which contains your storage account in classic mode there. Okay - so now you have the keys. Back in Azure Storage Tools, this is easy:

azcopy /Source:http://fullurltoyour/vhds/ /SourceKey:bunchofgoofollowedattheenndwith== /Destination:http://fullurltoyour/vhds/ /DestKey:adifferentbunchofgoofollowedattheendwith== /Pattern:nameofvhd.vhd

Note that you don't put the filename in the source/destination spot, but rather, the pattern. This let's you do lots of other neat stuff but that's for later - focus time! After a while (it's got a lot to move, in my case 127GB), it will say it's finished. You'll now construct a URL to that VHD in your head or notepad as you'll need it in a sec.

Now, FINALLY, we can create YE old VM. We'll need to do a few things to make it go, namely networking setup - this does it all:

$rgName = "name of your resourcegroup"
$location = "centralus"
$nicname = "Win10-NIC"
$subnet1Name = "Win10-Subnet"
$vnetName = "Win10-VNet"
$vnetAddressPrefix = ""
$vnetSubnetAddressPrefix = ""
$vmSize = "Standard_D2"
$osDiskName = $vmName + "OSDisk"
$vmName = "Win10-CPU"
$pip = New-AzureRMPublicIpAddress -Name $nicname -ResourceGroupName $rgName -Location $location -AllocationMethod Dynamic
$subnetconfig = New-AzureRMVirtualNetworkSubnetConfig -Name $subnet1Name -AddressPrefix $vnetSubnetAddressPrefix
$vnet = New-AzureRMVirtualNetwork -Name $vnetName -ResourceGroupName $rgName -Location $location -AddressPrefix $vnetAddressPrefix -Subnet $subnetconfig
$nic = New-AzureRMNetworkInterface -Name $nicname -ResourceGroupName $rgName -Location $location -SubnetId $vnet.Subnets[0].Id -PublicIpAddressId $pip.Id
$vm = New-AzureRMVMConfig -VMName $vmName -VMSize $vmSize
$vm = Add-AzureRMVMNetworkInterface -VM $vm -Id $nic.Id
$osDiskUri = ""
$vm = Set-AzureRMVMOSDisk -VM $vm -Name $osDiskName -VhdUri $osDiskUri -CreateOption attach -Windows

Once that is done, you can actually create the VM:

New-AzureRMVM -ResourceGroupName $rgName -Location $location -VM $vm -Verbose

With a bit of luck (and no typos), you should get a Deployment Status "OK" back after a few minutes. You can now start it, wait a few minutes and connect!

I suggest you read through the details of that big block o PowerShell - lots of functionality and power there to customize things. The main thing I was going for, again, was to not use a Template, not use a Deployment Image but attach to an existing VHD and make sure to put it into a Resource group. At the end of the process, I have a nice pretty Resource Group with all my stuff in it that I can now secure and give access to, report on individually, etc!

Too hard? Yes. Powerfull and fun? Much!