You can easily Start and Stop Virtual Machines (VMs) through the Azure Portal. Previously, I’ve written about the importance of Stopping unused VMs to save money and place them in a “Stopped (Deallocated)” state. While it’s easy and simple to do through the Azure Portal, it’s also time consuming if you have multiple VMs; especially if you have a dozen or more VMs. The following Azure CLI 2.0 tip will show you how you can easily use the Azure CLI to Start and Stop multiple VMs with a single command!
Before we get into how to Start, Stop and Deallocate Virtual Machines (VMs) in batches, we must first cover the basics of Starting, Stopping and Deallocating VMs one at a time. After those commands are defined and demonstrated, then you’ll have the foundation necessary to extend on that to do the batching. Please be patient as you read through as you’ll need to step through this to fully understand the end result. And, you’ll be glad you did once you get there as this will really enable you to be immensely more productive in your management of Azure Virtual Machines when it comes to Starting, Stopping, and Deallocating them.
Stop a VM with Azure CLI
Here’s the simple command you can use to Stop a VM using the Azure CLI 2.0:
# command format
az vm stop --name {vm name}
--resource-group {resource group name}
# usage example
az vm stop --name MyVM
--resource-group MyVMGroup
Here’s a description of the parameters to pass into he “az vm stop” command:
-n / –name
The name of the Azure Virtual Machine.
-g / –resource-group
The name of the Azure Resource Group that contains the Virtual Machine.
Remember that Stopping a VM will still incur the Virtual Machine instance size cost. In the stopped state you will still be holding on to the underlying resource reservation (CPU, Memory, etc) within the Azure data center. In order to stop paying for the VM Instance you need to Deallocate the VM instead. You can see a command for this below.
Start a VM with Azure CLI
Here’s the simple command you can use to Start a VM using the Azure CLI 2.0:
# command format
az vm start --name {vm name}
--resource-group {resource group name}
# usage example
az vm start --name MyVM
--resource-group MyVMGroup
Here’s a description of the parameters to pass into he “az vm start” command:
-n / –name
The name of the Azure Virtual Machine.
-g / –resource-group
The name of the Azure Resource Group that contains the Virtual Machine.
Deallocate a VM with Azure CLI
Here’s the simple command you can use to Deallocate a VM using the Azure CLI 2.0:
# command format
az vm deallocate --name {vm name}
--resource-group {resource group name}
# usage example
az vm deallocate --name MyVM
--resource-group MyVMGroup
Here’s a description of the parameters to pass into he “az vm deallocate” command:
-n / –name
The name of the Azure Virtual Machine.
-g / –resource-group
The name of the Azure Resource Group that contains the Virtual Machine.
Start, Stop, Deallocate Virtual Machines by ID
You could run a single command for each VM to Start, Stop, or Deallocate them one at a time. While this is much easier than using the Azure Portal UI to do the same task, it’s still fairly cumbersome when you have many VMs you need to manage all at the same time. Luckily, the Start, Stop, and Deallocate VM commands support a parameter named “–ids” that allows you to pass in the IDs of multiple Azure VMs to apply that command to all at once.
# command format
az vm start --ids {virtual machine ids}
az vm stop --ids {virtual machine ids}
az deallocate --ids {virtual machine ids}
# usage example
az start --ids "/subscriptions/a35d316a-2a2a-48e2-8834-55481f7bbb48/resourceGroups/WIN16VM/providers/Microsoft.Compute/virtualMachines/Win16VM"
az stop --ids "/subscriptions/a35d316a-2a2a-48e2-8834-55481f7bbb48/resourceGroups/WIN16VM/providers/Microsoft.Compute/virtualMachines/Win16VM"
az deallocate --ids "/subscriptions/a35d316a-2a2a-48e2-8834-55481f7bbb48/resourceGroups/WIN16VM/providers/Microsoft.Compute/virtualMachines/Win16VM"
While you can explicitly pass in the IDs of the VMs you want to run the command against, it’s a still a bit cumbersome to do. The Azure CLI 2.0 makes it extremely easy to pass in the IDs for multiple Virtual Machines by specifying another Azure CLI command to run to generate the value passed in.
Get List of Virtual Machine IDs
First, in order to pass in the IDs, you need to gather the IDs of the VM’s you are looking to run the command against. To do this you can use the “az vm list” command in combination with a few different parameters.
# usage example
az vm list --query "[].id"
-o tsv
The above command will output the IDs of ALL Virtual Machine you have access to on your Azure Subscription. Here’s a brief description of the parameters used and what action they are performing on this specific query:
–query “[].id”
This “–query” parameter is being used in this case to select only the “id” for all the VMs. So rather than return the full information or JSON for the VMs it’s going to only return their IDs.
-o tsv
This “-o” parameter is being used to modify the Output of the command. By passing the value of “tsv” to the Output parameter it’s instructed to return the results of the command in a Tab Delimited format. In this case since we’re only selecting the IDs of the VMs then its going to return a standard list of those IDs.

There are few times where you’ll want to be running a command against ALL the VMs in your Azure Subscription. In the majority of use cases you’ll need to filter this list down some to select the IDs of just the Virtual Machines you want to run the command against. To do this you can use the “–resource-group” parameter to select the VMs from a particular Resource Group.
# command format
az vm list --query "[].id"
-o tsv
--resource-group {resource group name}
# usage example
az vm list --query "[].id"
-o tsv
--resource-group MyVMGroup
You can also use the Linux “grep” command to perform filtering on the ID list that the “az vm list” command returns:
# usage example
az vm list --query "[].id"
-o tsv | grep "Test"
The above example shows passing the result of the “az vm list” command to “grep” which is then filtering that result and returning just the items that contain the string passed in. In this example, it’s filtering out all but the VM IDs that contain the string “Test”.

Start, Stop, Deallocate Multiple VMs at Once
Now we can put the above commands together to be able to easily Start, Stop, and Deallocate multiple Virtual Machines all at once with a single Azure CLI 2.0 command:
# example usage
az vm start --ids $(
az vm list --query "[].id"
-o tsv | grep "Test"
)
az vm stop --ids $(
az vm list --query "[].id"
-o tsv | grep "Test"
)
az vm deallocate --ids $(
az vm list --query "[].id"
-o tsv | grep "Test"
)

Using these techniques you will be able to much more easily Start, Stop, and Deallocate multiple Azure Virtual Machines using a single, or at least fewer, Azure CLI 2.0 commands. This should help you be a fair amount more productive when it comes to managing these actions against your Azure Virtual Machines.
Happy scripting!
Chris, very nice thank you, was able to get this up and running a lot quicker in Bash. Like Powershell though, each command will wait for the completion of the previous one. So for example the dealloc (in a resource group with say for example 4 VM’s in it) will issue the command for VM number 1, wait, then move onto VM 2 etc. which takes ages. It is still far quicker to do all this by-hand in the Azure GUI, rather than wait 20 minutes for it to complete (and sometimes the Azure CLI times out due to a perceived inactivity!!)
It would be great to be able to (a) stop all VM’s at once, then (b) de-allocate all VM’s at once, rather than round-robin through them. As I mentioned it is quicker by about 15 minutes to do this in the GUI than it is via scripting.
This example actually works in serial so is too slow for any non-trivial deployment.
You can do it in parallel using xargs. Windows users should just install bash…
Say you have a bunch of vms: cheezburger-01…..cheezburger-99
seq -f “%02g” 1 99 | xargs -P 16 -L 1 bash -c ‘az vm start -g whatever -n cheezburger-$0’
Yeah the CLI barfs errors sometimes, but this does work for 16 in parallel. Going higher than 16 won’t work reliably from what I have tested.
Or you can simply use Cloud Shell from inside the Azure portal (the >_ button on the top in your browser when logged into the portal) and run this command to shutdown or shutdown and deallocate all vms in your subscription.
//stop and keep provisioned all VMs
> Get-ChildItem ‘Azure:/YOUR_SUBSCRIPTION_NAME_HERE/VirtualMachines/’ | Stop-AzureRmVM -StayProvisioned -Force -AsJob
//stop and Deallocate all VMs
> Get-ChildItem ‘Azure:/YOUR_SUBSCRIPTION_NAME_HERE/VirtualMachines/’ | Stop-AzureRmVM -Force -AsJob
Thanks for the PowerShell tips for added context.
Hey Chris,
Wondering if there is a way to query the lastreboot time for the VM. I do not see a last reboot in the VM properties. Maybe you have some ideas? I am trying to extract when was the last time any VM under my subscription was rebooted.
As far as I know the Azure VM resource provider doesn’t expose this information. However, you can write a script to run on the VM itself to query this from the operating system.
az vm stop –no-wait –ids $(
az vm list –query “[].id”
-o tsv | grep “Test”
)
This will stop all of them simultaneously without waiting. It’s the fastest way to do it.