Get Ubuntu 16.04 VMs in Azure with PowerShell
Ubuntu 16.04 is going End Of Life at the end of April 2021, so without a paid-for subscription there won’t be any new security updates. We can use a couple of methods in PowerShell to list affected VMs in a tenancy.
Method 1: Image-based Virtual machines
VMs built from images are the easier target - we can quickly look for VMs built on the UbuntuServer
image using the SKU 16.04-LTS
1Get-AZVM | where {$_.StorageProfile.ImageReference.Offer -eq "UbuntuServer"
2 -and $_.StorageProfile.ImageReference.Sku -eq "16.04-LTS"}
Method 2: Manually built VMs
VMs which have been manually installed/modified, or perhaps arrived in Azure via a lift-and-shift operation from elsewhere may not be tied to an image, therefore looking up the OS version tied to the image doesn’t work. In these cases we can use the Azure Agent to interrogate the guest OS.
In the case of Ubuntu 16.04, the file /etc/osrelease
contains the Ubuntu version, so we can check for the presence of Ubuntu 16.04
in that file. The cmdlet Invoke-AzVmRunCommand
can be used to do this remotely assuming that the logged in account has permissions to do so on the VM.
Invoke-AzVmRunCommand
needs a script file to be run, so we’ve prepared the following file and saved it as ubuntuversion.sh
.
1cat /etc/osrelease
Breaking down the process, we’re searching each VM in the current context:
1foreach ($VM in Get-AZVM ....
And filtering to just the Linux VMs …
1Where-Object {$_.StorageProfile.OsDisk.OsType -eq "Linux"
… which are powered on.
1(Get-AZVM -Name $_.Name -ResourceGroupName $_.ResourceGroupName -Status).Statuses.Code -contains "PowerState/running"
With each of the VMs in this list we’re running our pre-prepared script which returns /etc/osrelease
to us
1$result=invoke-azvmruncommand -vmname $VM.Name -ResourceGroupName $VM.ResourceGroupName -CommandId "RunShellScript" -ScriptPath .\ubuntuversion.sh
And then if that file contains Ubuntu 16.04
we’re writing the VM Name to the console
1 if($result.value.item(0).Message.ToString().Contains("Ubuntu 16.04")){$VM.Name}
So altogether the snippet looks like:
1foreach ($VM in Get-AZVM -Status |
2 Where-Object {$_.StorageProfile.OsDisk.OsType -eq "Linux" -and (Get-AZVM -Name $_.Name -ResourceGroupName $_.ResourceGroupName -Status).Statuses.Code -contains "PowerState/running"}) {
3 $result=invoke-azvmruncommand -vmname $VM.Name -ResourceGroupName $VM.ResourceGroupName -CommandId "RunShellScript" -ScriptPath .\ubuntuversion.sh ;
4 if($result.value.item(0).Message.ToString().Contains("Ubuntu 16.04")){$VM.Name}
5}
When run this will produce a list of the powered on Azure VMs running Ubuntu 16.04LTS in the current context/subscription of the PowerShell session.
Known Issues
This will fail if
- The user running the script has insufficient rights to run a script in the Guest OS as laid out here: docs.microsoft.com/en-us/azure/virtual-machines/linux/run-command
- The Azure agent is not installed, or not configured correctly. This will fail with
VMAgentStatusCommunicationError
as follows.
1Long running operation failed with status 'Failed'. Additional Info:'VM 'myVMName' has not reported status for VM agent or extensions.
2Verify that the OS is up and healthy, the VM has a running VM agent, and that it can establish outbound connections to Azure storage.
3Please refer to https://aka.ms/vmextensionlinuxtroubleshoot for additional VM agent troubleshooting information.'
4ErrorCode: VMAgentStatusCommunicationError