“Just use PowerShell to create your virtual machine…” they said.
“It’ll be easy,” they said.

Unknown

Creating an Azure Virtual Machine with PowerShell is actually kind of complicated. But after I show you how to build an Azure Virtual Machine with PowerShell, you’ll understand why each step is needed, and I promise it will make sense.

The steps along the way…

  • Create a placeholder for all the Azure Virtual Machine settings
  • Define storage
  • Define networking
  • Choose VM Size
  • Choose Operating System
  • Create the VM!

By the way… I teach a course on using PowerShell to create Azure resources

PowerShell on the Cloud – Using PowerShell and the Azure module to manage Azure Infrastructure Services – Packt Publishing
(affiliate link through Udemy)

Choose a VM Size

The best way to choose your VM size is to see all of your options in a list.

When you create your VM later, you’ll reference this VMSize object.

#Throughout this, I use "East US" as a location. This works just as well 
#  in any region.
Get-AzVMSize -Location 'East US'
# Find the size you like? Save it as $VMSize
$VMSize = Get-AZVmSize -Location "east us" | `
  Where-Object Name -eq "Standard_D1_v2"

Creating the Azure VM Object

This $VMSettings object will get all of the settings that we’re going to customize.

$VMSettings = New-AzureRmVMConfig -VMName "MyVM" -VMSize $VMSize.Name 

Define Storage

Want to add data disks to your virtual machine? Or just have one big OS disk?

Here’s how to do it:

# Set the size of the OS disk.
# Also set that the OS disk is going to be created from an image
Set-AzVMOSDisk -VM $vmSettings `
  -Name "MyVM-os" -Windows `
  -DiskSizeInGB 80 `
  -CreateOption FromImage
# Add a data disk
Add-AzVMDataDisk -VM $vmSettings -Name "MyVM-data" `
  -DiskSizeInGB 100 `
  -CreateOption Empty `
  -Lun 1

Define Networking

Let’s assume that you wanting your VM to join an existing Virtual Network. That’s when it gets hard, anyway, so that’s what I’ll teach you to do.

To make it work, you need to get all the settings from the virtual network, then use those settings to create a new Network Interface.

Later, you’ll add the Network Interface to the VM that you’re going to create.

# - Network settings 
# - You always want to specify the Resource Group
$NetRG = Get-AzureRMResourceGroup "NetworkResourceGroup"
# Get the Virtual Network. Notice I'm using the pipeline to pass in 
# the resource group
$DemoNet = $NetRG | Get-AzureRMVirtualNetwork -Name "DemoNetwork"
# This uses the first subnet in the Virtual Network. 
# Adjust this for your use case
$Sub0 = $DemoNet.Subnets[0]
# Create the Network Interface, save it in a variable
$NIC = $VMRG | New-AzureRmNetworkInterface -Name "SQLVM-Nic" -SubnetId $Sub0.Id
# This is what you just created
$NIC

Choose an Operating System (VM Image)

VM Images are complex: they are uploaded by a publisher, and a publisher can have lots of types of VM Images that they offer. Even those different offers can have features or licensing applied (SKU). And finally, there can be individual updates to those SKUs, like “latest” or “nightly”.

All of those components come together to make the “Image”.

The lame part is that there’s no way to search for “Images” without knowing all of the other components.

To be clear: There’s no way to search for “Images named Windows Server 2019” without knowing the Publisher name, the offer name, and the SKU.

A Nightmare...

BUT… If you remember the flow of the images, you CAN get through this.

Just remember:

  • Publishers make 1 or more offers
  • Offers have 1 or more SKUs
  • SKUs have 1 or more Images
  • You can’t search for Images unless you know all three of: Publisher, Offer, and Sku.
# Get the publisher you're looking for.  Careful, there's like 1,000
Get-AzVMImagePublisher -Location 'East US'  | Select-Object -First 10
# After finding the publisher, get their offers
Get-AzVMImageOffer -Location "East US" -PublisherName "MicrosoftSQLServer"
# Search for SKUs with the publisher and offer
Get-AzVMImageSku -Location "East US" -PublisherName "MicrosoftSQLServer" -Offer "SQL2017-WS2016"
# NOW you can search for your image
Get-AzVMImage -Location "East US" -PublisherName "MicrosoftSQLServer" -Offer "SQL2017-WS2016" -Skus "SQLDEV"

Another way is to use each object returned in those statements to feed into the next.

$Pub = Get-AzVMImagePublisher -Location 'East US' | Where-Object PublisherName -eq "MicrosoftWindowsServer"
$Offer = $Pub | Get-AzVMImageOffer | Where-Object Offer -eq "WindowsServer"
$Sku = $Offer | Get-AzVMImageSku | Where-Object Skus -eq "2019-Datacenter"
$Image = $Sku | Get-AzVMImage | Select-Object -Last 1
# $Image now has all of the properties you need
# - publisher
# - offer
# - sku
# - image

Either way, you should end up with an IMAGE that you want to apply to your VM.

Putting it all together to create the Azure VM with PowerShell

# Start by creating a resource group. 
$rg = New-AzResourceGroup -Location "east us" -Name AzVmPowerShellDemo
# Choose a VM Size
$VMSize = "Standard_D1_v2"
# Create the VM Configuration Object
$VMSettings = New-AzVMConfig -VMName "MyVM" -VMSize $VMSize 
# Create a username and password for logging into the VM
$AdminLogin = Get-Credential "LocalAdmin"
# Add the OS image
$Image = Get-AzVMImage `
  -PublisherName "MicrosoftWindowsServer" `
  -Offer "WindowsServer" `
  -Skus "2019-DataCenter" `
  -Location "east us" | Select-Object -Last 1
$Image | Set-AzVmSourceImage -VM $VMSettings
# Configure the operating system. 
Set-AzVMOperatingSystem -VM $VMSettings `
   -Windows `
   -ComputerName "MyVm" `
   -Credential $AdminLogin
# Configure the Disks
Set-AzVMOSDisk -VM $vmSettings `
  -Name "MyVM-os" -Windows `
  -DiskSizeInGB 80 `
  -CreateOption FromImage
Add-AzVMDataDisk -VM $vmSettings `
  -Name "MyVM-data" `
  -DiskSizeInGB 100 `
  -CreateOption Empty `
  -Lun 1
# - Create the network interface
$NetRG = Get-AzResourceGroup "NetworkResourceGroup"
$DemoNet = $NetRG | Get-AzVirtualNetwork -Name "DemoNetwork"
$Sub = $DemoNet.Subnets[0]
$NIC = $rg | New-AzNetworkInterface -Name "MyVM-Nic" -SubnetId $Sub.Id
# Add network to the VM
Add-AzVMNetworkInterface -VM $VMSettings -Id $NIC.Id
# Build the VM in the resource group
$rg | New-AzVm -VM $VMSettingsget

See how easy that was?