Azure – Finding VM Agent version

All Azure VMs usually have a VM Agent installed. But there can be situations where it is missing, such as when a VM was moved over to Azure or deployed from an appliance image.

I needed to find whether a VM has the agent installed or not. Using PowerShell one can do it thus:

Its important to add the -Status switch as well as the -ResourceGroup. Without either of these you won’t get the VMAgent property.

One thing I’ve started using more is the Azure REST API. I like it especially coz we have multiple subscriptions and I find it good being able to refer to a resource by its full path instead of changing subscriptions and then running a cmdlet against the resource. Also, you get all the properties and the reference document (the previous link) is awesome as it has all the endpoints and what to expect etc. You got to dig around though to find what endpoint to use, so that is a pain… but I feel this is the future and I am happy to spend some time digging around.

With Azure REST API I have to go with the VM Instance View endpoint. One would have thought it would be the VM Get endpoint, but that doesn’t have this info. The equivalent REST API cmdlet for the above would be:

Set the variables with the Subscription ID etc. of course.

It is a mouthful and seems more trouble than it’s worth, but it’s not. One gets used to it quickly.

Another cool thing I discovered recently is Azure Resource Graph. I couldn’t find a way of using that this purpose (create a list of all my VMs that are missing the agent, for instance). Reading Kusto gives me a headache so I didn’t try too hard either. :)

Updates

Somewhere between sleep and waking up the following morning I realized I didn’t have to solve the entire problem using Azure Resource Graph. Azure Resource Graph is a tool in my toolbox, it doesn’t have to be the only tool.

Here’s where I stumbled with Azure Resource Graph. If I have a basic query like:

(FYI: you can run in the Azure Resource Graph Explorer in the portal, or via PowerShell)

Then under the properties property in the output I have the following:

That seems to be the only InstanceView related information – similar to the REST API or the Get-AzVM -Status cmdlet above – but its missing details like the Agent version. I gave up at this point as I didn’t want to figure out how I can search other tables maybe that have the Agent info and do some Kusto magic to join them all together etc.

But what I realized later is that I can use Azure Resource Graph to get all my VMs, across all my subscriptions, that are powered on and then I can use the REST API to get the Agent version from them.

So here’s step 1:

At this point $vms should contain all the powered on VMs across all my subscriptions. There’s a catch though that while the portal returns all the results, the cmdlet returns only 100 by default (or 1000 at max) so once needs to do some jiggery pockery if using the cmdlet for such queries.

I came across an idea via this GitHub issue, so credits to that for what I am doing below.

The cool thing is that each entry of the $vms array now has a resource Id to the object. Like so: /subscriptions/<subId>/resourceGroups/<rgName>/providers/Microsoft.Compute/virtualMachines/<vmName>. This is the Id property I “project” as part of the Azure Resource Graph query.

Notice its similarity to the path I used with Azure REST API above. So now i can iterate over this array:

Above I am just emitting a list but one can modify this to output object that contain the Id property and agent status, which can then be consumed in other ways. For example:

This is powerful stuff! Imagine being able to run queries across all your subscriptions and resource groups. Yes you could do it in the past too but you’d have to enumerate subscriptions, resource groups, query against each VM to find the powered on ones and identify the agent version and so on. You are doing something similar here too but the difference being Azure Resource Graph can easily give you a list of powered on VMs across all subscriptions in a matter of milliseconds (I got some 1200+ results in 338ms) and then you gotta query each of them individually but that’s a way simpler code too thanks to the REST API.