Azure resource management

How to find stopped virtual machines in Azure

Find stopped virtual machines with Azure PowerShell and Resource Graph, read each machine's Status in the Azure portal, or run Altivane's Azure Virtual Machines report for power states.

By the Published

To find stopped virtual machines in Azure, read each machine's power state from Azure Resource Graph and keep the ones that aren't running. A machine stopped from inside its operating system is still allocated and billed for compute; only a deallocated machine stops compute charges, and both still pay for their disks.

Choose the method that fits the job
MethodBest fit
PowerShellA CSV of every machine that isn't running across your enabled subscriptions.
Admin centreA quick look at each machine's status in 1 list.
AltivaneRecommended for monthly cost reviews, with each machine's size, disks and power state in a workbook.

Before you start

Use an account with read access to the subscriptions, such as the Reader role: Resource Graph returns nothing for resources you can't read. Microsoft lists no licence for Resource Graph.

Know where the power state comes from. It is an extended property in Resource Graph, a preview feature, and it is the machine's last known state. In rare cases Azure can't give a power state, and the machine then has none. Machines in a scale set with Uniform orchestration are in the ComputeResources table, not in Resources, so the example leaves them out. The examples read and export; they don't start, stop or deallocate anything. The script's finally block disconnects the account and clears its saved Azure contexts.

Option 1

Find stopped virtual machines with PowerShell

Install the modules once. The script queries Resource Graph across the enabled subscriptions, follows every page of results, and saves each machine that isn't running.

PowerShell
Install-Module -Name Az.Accounts, Az.ResourceGraph -Repository PSGallery -Scope CurrentUser
PowerShell
$ErrorActionPreference = 'Stop'
Connect-AzAccount -ErrorAction Stop
try {
    $subscriptionIds = @(
        Get-AzSubscription | Where-Object State -eq 'Enabled' | Select-Object -ExpandProperty Id
    )
    if ($subscriptionIds.Count -eq 0) {
        Write-Output 'No enabled subscriptions are available to this account.'
        return
    }
    $query = @(
        'Resources'
        '| where type =~ "microsoft.compute/virtualmachines"'
        '| extend powerState ='
        'tostring(properties.extended.instanceView.powerState.displayStatus)'
        '| where powerState != "VM running"'
        '| project id, name, resourceGroup, subscriptionId, location, powerState,'
        'size = tostring(properties.hardwareProfile.vmSize)'
        '| order by id asc'
    ) -join ' '
    $rows = [System.Collections.Generic.List[object]]::new()
    $skipToken = $null
    do {
        $arguments = @{ Query = $query; Subscription = $subscriptionIds; First = 1000 }
        if ($skipToken) { $arguments.SkipToken = $skipToken }
        $page = Search-AzGraph @arguments
        foreach ($record in $page.Data) { $rows.Add($record) }
        $skipToken = $page.SkipToken
    } while ($skipToken)
    if ($rows.Count -eq 0) {
        Write-Output 'Every virtual machine in the enabled subscriptions is running.'
    } else {
        $rows | Select-Object name, powerState, size, resourceGroup, subscriptionId, location,
            @{ Name = 'deallocated'; Expression = { $_.powerState -eq 'VM deallocated' } }, id |
            Sort-Object deallocated, name |
            Export-Csv -Path './stopped-virtual-machines.csv' -NoTypeInformation -Encoding utf8
        Write-Output "$($rows.Count) machines saved to stopped-virtual-machines.csv."
    }
} finally {
    Disconnect-AzAccount | Out-Null
}

The CSV lists each machine that isn't running with its power state, size, resource group, subscription and location. Machines whose state isn't VM deallocated come first: most of them are still billed for compute. A machine that is starting, stopping or hibernated is listed too, so check its state again before acting on it.

Option 2

Check virtual machine status in the Azure portal

  1. Sign in to the Azure portal with an account that can read the subscriptions.
  2. Search for Virtual machines and open it.
  3. Select Add filter to narrow the list if you need to, such as to 1 resource group.
  4. Read Status for each machine. Stopped means it is still allocated and billed for compute; Stopped (deallocated) means it has released its hardware.

Leave without selecting Start or Stop. The list suits a quick look at a few machines; for a file across subscriptions to keep each month, use PowerShell or Altivane.

Common questions

Why is a stopped machine still on the bill?

A machine shut down from inside its operating system stays allocated on its host, so Azure keeps charging for compute. Stop it from the portal, PowerShell or another management tool to deallocate it. Altivane's Stop a virtual machine change stops and deallocates the machines you choose.

Does deallocating a machine end all its charges?

No. Its disks and some networking are still charged while it is deallocated. Disks a deleted machine left behind are a separate cost: see how to find unattached Azure disks.

Why does a machine have no power state?

Azure occasionally fails to return a power state. Run the query again later, or check the machine in Azure Resource Health.

Microsoft references

Technical references checked on 7 November 2026. The example scripts have been reviewed and syntax checked; they have not been run against a live tenant.

Talk to us about Altivane

Questions, or pricing? Get in touch.

Contact us