Azure Power Shell: Azure Virtual Machines for the command line junkie!

Web UI looks good and pretty but if you really want to get work done at scale, manage, automate and administer: command line is your way. As a command line junkie from the UNIX world I thought of exploring what Azure PowerShell had to offer. And boy, I was quite blown by the ease of use, functionality and flexibility it comes with. Through this tutorial series, I will take you through various scenarios and functionality on Azure that is made easy using Azure Power Shell.

imageThe first topic in this tutorial I covered was how to manage Azure Websites using power shell. This time we will be looking at how to manage Virtual Machines. Again, the usual the disclaimer: This is not a holistic compilation of all the functionality in Virtual Machines using PowerShell, but I will try and cover the most used ones!

(Note: This is a code heavy blog which essentially details out the various options available for VM Management using PowerShell)

Getting Started

As in the previous article, the start is still the same: Add your account and the subscription that you would want to use in the portal.

   1: Add-AzureAccount
   2: Get-AzureSubscription
   3: Select-AzureSubscription "Azure Pass" -CurrentStorageAccountName $storageAccount

Creating the Virtual Machine

There are 2 commands that you could use to create a virtual machine: New-AzureQuickVM and New-AzureVMConfig. The 2 cmdlets can both be used but New-AzureQuickVM (as the name might suggest) is a little limited in comparison to the additional flexibility and options that New-AzureVMConfig comes with. For example, using New-AzureQuickVM it is not possible to create VMs from disks or add end points such as a RDP/WINRM for Windows or SSH for Linux).

   1: #Using New-AzureQuickVM
   3: $adminUser = "[admin user name]"
   4: $password = "[admin password]"
   5: $serviceName = "contoso-vms"
   6: $location = "West US"
   7: $size = "Small"
   8: $vmName = "vm1"
   9: $imageFamily = "Windows Server 2012 R2 Datacenter"
  10: $imageName = Get-AzureVMImage |
  11: where { $_.ImageFamily -eq $imageFamily } |
  12: sort PublishedDate -Descending |
  13: select -ExpandProperty ImageName -First 1
  15: New-AzureQuickVM -Windows `
  16: -ServiceName $serviceName `
  17: -Name $vmName `
  18: -ImageName $imageName `
  19: -AdminUsername $adminUser `
  20: -Password $password `
  21: -Location $location `
  22: -InstanceSize $size

New-AzureConfigureVM essentially creates a local configuration object that is passed on to other cmdlets. and using this combination of cmdlets this is accomplished as shown below.

   1: $adminUser = "adarsha"
   2: $password = "<admin password>"
   3: $serviceName = "powershellVMCloudService"
   4: $location = "East US"
   5: $size = "Small"
   6: $vmName = "powershellVM"
   8: $imageFamily = "Windows Server 2012 R2 Datacenter"
   9: $imageName = Get-AzureVMImage | where { $_.ImageFamily -eq $imageFamily } | sort PublishedDate -Descending | select -ExpandProperty ImageName -First 1
  11: New-AzureVMConfig -Name $vmName -InstanceSize $size -ImageName $imageName |
  12: Add-AzureProvisioningConfig -Windows -AdminUsername $adminUser -Password $password |
  13: Add-AzureDataDisk -CreateNew -DiskSizeInGB 10 -LUN 0 -DiskLabel "data" |
  14: Add-AzureEndpoint -Name "SQL" -Protocol tcp -LocalPort 1433 -PublicPort 1433 |
  15: New-AzureVM -ServiceName $serviceName -Location $location

If you do not wish to create such a long command line argument as it makes it difficult in debugging purposes, you can easily do this by reusing the configuration object variable:

   1: #Get the configuration object
   2: $VMObject = New-AzureVMConfig -Name "powershellVM" -InstanceSize $size -Image $imageName
   4: #Add the disk
   5: $VMObject| Add-AzureProvisioningConfig -Windows -AdminUsername $adminUser -Password $password |
   6: Add-AzureDataDisk -CreateNew -DiskSizeInGB 10 -LUN 0 -DiskLabel "data"
   8: #Add Endpoints
   9: $VMObject | Add-AzureEndpoint -Name "SQL" -Protocol tcp -LocalPort 1433 -PublicPort 1433 |
  11: #Add the VM to a cloud service which helps in the management
  12: $VMObject |  New-AzureVM -ServiceName $serviceName -Location $location

If you want to create a VM from a disk rather than an existing image, you can specify that using the ‘DiskName’ parameter rather than ‘ImageName’ parameter. In order to check if OS disks exists, you could use the Get-AzureDisk command.

For windows, there will always be a username and login, but in Linux machines there is an option to login without using the password. This can be done by ensuring the correct SSH certificate is uploaded on the cloud service that hosts the virtual machine. The following are the additional commands that need to be executed for you to create the required certificates and upload it on the cloud service.

   1: #Create the certificate
   2: openssl.exe req -x509 -nodes -days 365 -newkey rsa:2048 -keyout myPrivateKey.key -out myCert.pem
   4: #Add Certificate to the Cloud Service
   5: $certPath = "C:\MyCerts\myCert.pem"
   6: $cert = Get-PfxCertificate -FilePath $certPath
   7: Add-AzureCertificate -CertToDeploy $certPath -ServiceName $service
   9: #Let Azure know the configuration that needs to be added to the created Linux VM
  10: $sshKey = New-AzureSSHKey -PublicKey -Fingerprint $cert.Thumbprint -Path "/home/$linuxUser/.ssh/authorized_keys"
  11: $VMObject | Add-AzureProvisioningConfig -SSHPublicKeys $sshkey #Note: the Azure configuration is added to the created VM using the New-AzureVMConfig command

The following additional functionalities can be helpful to know:

   1: #Add TimeZone
   2: $VMObject | Add-AzureProvisioningConfig –TimeZone "Tokyo Standard Time"
   4: #Deploy Certificates
   5: $VMObject | Add-AzureProvisioningConfig -X509Certificates $cert
   7: #Resetting password on first login
   8: $VMObject | Add-AzureProvisioningConfig –ResetPasswordOnFirstLogon

Managing the lifecycle of the VM:

   1: #Stop the VM, if last VM in the Cloud Service, specify -Force to lose the Static Ip associated
   2: Stop-AzureVM -ServiceName $serviceName -Name $vmName
   4: #Start VM
   5: Start-AzureVM -ServiceName $serviceName -Name $vmName
   7: #Deleting VMs
   8: Remove-AzureVM -ServiceName $serviceName -Name $vmName
  10: #Deleting Cloud Service deletes all VMs in it too
  11: Remove-AzureService -ServieName $serviceName -Name $vmName -Force -DeleteAll

Disk and Image Management

Disk management is one of the important considerations in any organizations. One can either use third party tools or use Power Shell cmdlets as shown below:

   1: #Upload a VHD in a Storage Account
   2: $storage = "[storage account name]"
   3: $storagePath = "https://$"
   4: $sourcePath = "C:\mydisks\myosdisk.vhd"
   5: Add-AzureVhd -Destination $storagePath -LocalFilePath $sourcePath
   7: #Using Save-AzureVHD: This is different as the source is now a URI and local path is the destination of where it will be downloaded
   8: Save-AzureVhd -Source $storagePath -LocalFilePath $localPath

Image Management is a quite easy and can be pretty crucial to create images of your environments for later deployments. There are 3 different kinds of images that can be created. Generic images are created using tools such as Sysprep.exe (Windows) or Azure Agent (waagent on Linux). The idea is simple, create your environment once and replicate across your farm of VMs.

   1: #Create a Generic image after having run Sysprep or WAAGENT on respective machine.
   2: Save-AzureVMImage -ServiceName $serviceName `
   3: -Name $vmName `
   4: -ImageName $imageName `
   5: -ImageLabel $imageLabel `
   6: -OSState Generalized
   8: #Create Specialized image without running sysprep or waagent
   9: Save-AzureVMImage -ServiceName $serviceName `
  10: -Name $vmName `
  11: -ImageName $imageName `
  12: -ImageLabel $imageLabel `
  13: -OSState Specialized
  15: #Create legacy operating system image without keeping the information of the data disk
  16: Save-AzureVMImage -ServiceName $serviceName `
  17: -Name $vmName `
  18: -ImageName $imageName `
  19: -ImageLabel $imageLabel `

Creating disks and images from VHDs:

   1: #Create OS Disk from VHD
   2: $storage = "[storage account name]"
   3: $storagePath = "https://$"
   4: $diskName = "MyOSDisk"
   5: $label = "MyOSDisk"
   6: Add-AzureDisk -DiskName $diskName -Label $label -MediaLocation $storagePath -OS Windows
   8: #Create image from VHD
   9: $storage = "[storage account name]"
  10: $storagePath = https://$
  11: $imageName = "MyGeneralizedImage"
  12: $label = "MyGeneralizedImage"
  13: Add-AzureVMImage -ImageName $imageName `
  14: -MediaLocation $storagePath `
  15: -OS Windows

Just keep in mind that Save-AzureVMImage creates images from VMs where as Add-AzureVMImage creates the image from the VHD. In terms of managing your disks the following cmdlets can help you:

   1: #Adding data disks to your VM
   2: $serviceName = "PowerShellCS"
   3: $vmName = "PowerShellVM"
   4: Get-AzureVM -ServiceName $serviceName -Name $vmName |
   5: Add-AzureDataDisk -CreateNew `
   6: -DiskSizeInGB 500 `
   7: -LUN 1 `
   8: -DiskLabel "data 2" |
   9: Update-AzureVM
  11: #View the data disks attached to your VM
  12: Get-AzureVM -ServiceName $ServiceName -Name $VMName | Get-AzureDataDisk
  14: #Delete image
  15: Remove-AzureVMImage -ImageName "MyGeneralizedImage" -DeleteVHD
  17: #Delete disks
  18: Remove-AzureDisk -DiskName "mydatadisk" -DeleteVHD

Configuring your VM

There are several ways that you can configure your VM. The following code samples cover custom script extension, Desired State Configuration, access and puppet extensions:

   1: #Custom Script Extension during VM Provisoining
   2: $VMObject | Set-AzureVMCustomScriptExtension -FileUri $scriptUri `
   3: -Run $scriptname `
   4: -Argument $scriptArgument | 
   5: New-AzureVM -ServiceName $ServiceName -Location $location
   7: #Custom Script Extension after VM is provisioned
   8: Get-AzureVM -ServiceName $ServiceName -Name -$VMName |
   9: Set-AzureVMCustomScriptExtension -FileUri $ScriptUri -Run $ScriptName  -Argument $ScriptArgument |
  10: Update-AzureVM
  12: #Setting Desired State Configuration during provisioning. (If VM already exists use the above analogy to update VM)
  13: $ConfigArchieve = "<DSC script>"
  14: $ConfigName = "<DSC Name>"
  15: $VMObject | Set-AzureVMDscExtension -ConfigurationArchieve $ConfigArchieve -ConfigurationName $configName |
  16: New-AzureVM -ServiceName $ServiceName -Location $Location
  18: #Remove DSC Extension
  19: Get-AzureVM -ServiceName $serviceName -Name $vmName |
  20: Remove-AzureVMDscExtension |
  21: Update-AzureVM
  23: #Puppet Extensions
  24: $VmObject | Set-AzureVMPuppetExtension -PuppetMasterServer $puppetServer

Monitoring and Diagnostics

Finally, most of the diagnostics and monitoring happens in the management portal. However, using the following, we are able to enable diagnostics.

   1: $configPath="c:\Diagnostics\diagnosticsConfig.xml"
   2: $storageContext = New-AzureStorageContext -StorageAccountName $storage -StorageAccountKey $accountKey
   3: Get-AzureVM -ServiceName $serviceName -Name $vmName |
   4: Set-AzureVMDiagnosticsExtension -DiagnosticsConfigurationPath $configPath `
   5: -Version "1.*" `
   6: -StorageContext $storageContext |
   7: Update-AzureVM -ServiceName $serviceName -Name $vmName


Hope this was helpful to at least get an idea of the functionalities that is available for virtual machine management using the power shell. One of the most important places to explore is configuration of the VM using script extensions or DSC or chef or puppet. These help in automating and managing environments. All of this also comprises of the bigger family of DevOps where Docker is the buzz these days. There are lot of other resources that you could dig into to learn more, write your scripts using the cmdlets and automate. Automation and efficient DevOps are the key growth drivers in the industry, so “Keep Calm and VMPowerShell it”.


Comments (1)

  1. Prasad says:

    good article

Skip to main content