Find unused Azure resources with Azure Resource Graph, then confirm ownership, dependencies and activity before deleting them. Resource Graph identifies unattached infrastructure across subscriptions, but unattached does not mean unnecessary. Use Azure Monitor to assess activity and Azure Cost Management to establish which candidates are generating charges.
Start with an inventory rather than a deletion script. Separate resources that can be removed permanently from workloads that need resizing, scheduled shutdown or continued retention.
Key takeaways for Azure resource cleanup
- Treat Resource Graph results as review candidates, not approval to delete.
- Distinguish allocated compute, retained storage and contractual commitments when calculating savings.
- Record owner approval, recovery requirements and the exact resource IDs before removal.
- Automate discovery first, then introduce shutdown schedules for explicitly approved workloads.
Find unused Azure resources with Resource Graph
Azure Resource Graph queries Azure resource inventory at scale across subscriptions using Kusto Query Language (KQL). In the Azure portal, open Resource Graph Explorer, select the intended subscriptions and run each query below separately.
Start with Reader access at the required scope. Results only cover resources the querying identity can access, so a successful query does not prove the entire estate was examined.

The Resources table contains configuration records, not historical CPU or transaction metrics. Microsoft’s advanced Resource Graph examples demonstrate how queries can combine resource properties, tags and relationships.
Export results with resource IDs, subscription IDs and resource groups. Add ownership and cost information before making changes.
Identify unattached disks and public IP addresses
Find managed disks without an attached VM
This query identifies disks where managedBy is empty or diskState is Unattached:
Resources
| where type =~ 'microsoft.compute/disks'
| where isempty(managedBy)
or properties.diskState =~ 'Unattached'
| project id, name, resourceGroup, subscriptionId,
diskState = tostring(properties.diskState)
Query matches may be orphaned resources, but they are candidates for review, not automatic deletions. An unattached managed disk can still incur storage charges. However, it may contain retained application data, support a recovery workflow or have been detached temporarily during maintenance.
Review shared-disk references, Azure Site Recovery dependencies and backup requirements before deletion. The open-source Azure orphan-resource query collection highlights Site Recovery exclusions, which matter when adapting discovery queries.
Record the data owner’s decision. Do not create a snapshot automatically unless its retention purpose and additional cost are justified.
Find unassociated public IP addresses
Public IPs without an IP configuration or NAT gateway association are candidates for review:
Resources
| where type =~ 'microsoft.network/publicipaddresses'
| where isempty(properties.ipConfiguration.id)
and isempty(properties.natGateway.id)
| project id, name, resourceGroup, subscriptionId,
address = tostring(properties.ipAddress)
Inspect service-managed associations, DNS records, partner allowlists and planned deployments. Deleting an address can release it; recreating the resource does not guarantee the same address.
Review orphaned networking and availability resources
Find network security groups without attachments
This query selects network security groups (NSGs) with no network interfaces or subnets attached:
Resources
| where type =~ 'microsoft.network/networksecuritygroups'
| where coalesce(array_length(properties.networkInterfaces), 0) == 0
and coalesce(array_length(properties.subnets), 0) == 0
| project id, name, resourceGroup, subscriptionId
An unattached NSG may contain approved rules for a forthcoming deployment. Compare it with infrastructure-as-code definitions and the network design before removing it.
Find detached network interfaces
Exclude interfaces associated with either a VM or a private endpoint:
Resources
| where type =~ 'microsoft.network/networkinterfaces'
| where isempty(properties.virtualMachine.id)
and isempty(properties.privateEndpoint.id)
| project id, name, resourceGroup, subscriptionId
Review associated public IPs, DNS settings and application configuration. An unused network interface does not establish that its connected resources can all be deleted.
Find empty availability sets
Availability sets with no VM members have a virtualMachines array length of 0. This query also handles an omitted array:
Resources
| where type =~ 'microsoft.compute/availabilitysets'
| where coalesce(array_length(properties.virtualMachines), 0) == 0
| project id, name, resourceGroup, subscriptionId
Confirm that no virtual machines use the set and that deployment templates no longer reference it. Removing empty availability sets, ordinary network interfaces and NSGs mainly simplifies management; these resources do not normally carry standalone charges.
Prioritise chargeable disks, public IPs and running compute when the immediate objective is reducing expenditure.
Use monitoring to distinguish idle resources from required ones
Assess VM activity beyond CPU
A low CPU utilization reading is a review signal, not proof that a VM is redundant. File servers, authentication services and disaster recovery systems can remain necessary despite limited processing activity.
A threshold such as CPU below 5% over 30 days can produce a shortlist. Review network traffic, disk activity, application schedules and recovery responsibilities alongside it. Include month-end processing and other infrequent business tasks.
Azure Advisor can identify optimisation opportunities, whilst Azure Cost Management shows the expenditure attached to each candidate. Neither replaces the workload owner’s decision.
Assess storage transactions and data purpose
For storage accounts, review Azure Monitor transaction metrics across the Blob, File, Queue and Table services actually in use. Use Total aggregation over a period that includes relevant operating cycles.
Inspect object or file modification dates separately. Reads do not necessarily update modification timestamps, and account configuration dates do not establish when stored data was last accessed.
Use configured Azure Monitor Logs for additional diagnostic evidence. Missing logs do not prove inactivity.
Archive data, recovery copies and retained business records can legitimately show little activity. Review purpose and retention before removal; our guidance on Azure Storage security also covers ownership, access and recovery controls.
Confirm ownership and dependencies before removal
Owner approval should identify the business purpose, affected application, retention requirements and recovery route. A tag naming a department is insufficient if nobody accepts responsibility for the decision.

Use a documented removal sequence:
- Record the exact resource ID, owner, current cost and reason for removal.
- Review dependencies in application configuration, deployment templates, DNS, network rules, identities, backup and recovery systems.
- Preserve required records and agree a recovery method, observation period and change window.
- Obtain approval, remove the selected resource and test the affected services.
- Review remaining dependencies and charges, then update the asset register and next review date.
Where a reversible stop or configuration change is available, use it before permanent deletion. Do not simulate retirement by weakening authentication or exposing data.
In the portal, open the approved resource, select Delete and review the confirmation carefully. Avoid deleting an entire resource group unless every contained resource has been assessed. Update infrastructure-as-code definitions so the next deployment does not recreate retired resources.
Separate stopping compute from ending all charges
A VM stopped inside its operating system can remain allocated and billed. Deallocation releases its compute allocation; the required status is Stopped (Deallocated).
For command-line operations, the Azure CLI reference distinguishes az vm stop from az vm deallocate. The former does not release the compute allocation.
The remaining billing position depends on the resource.
| Action or resource | Cost implication |
|---|---|
| Deallocated VM | VM compute usage charges stop. |
| Managed disks and snapshots | Retained storage remains chargeable. |
| Backups and monitoring data | Storage, retention or other applicable charges can continue. |
| Reservations or reserved capacity | Existing commitments do not disappear when a VM stops. |
| Stopped Azure App Service app | A paid hosting plan can remain billable. |
An NSG deletion may improve housekeeping without changing the bill. Conversely, stopping an application can leave its underlying hosting capacity chargeable.
Use actual costs and commitments to confirm whether a change is cost-efficient. Freed capacity may benefit another workload without reducing the current invoice. After deletion, review retained disks, snapshots, backup data and public IPs individually rather than assuming the parent resource removed them.
Automate approved shutdowns and recurring reviews
Use tags and a managed identity for VM shutdown
An Azure Automation runbook can find VMs tagged AutoShutdown=Enabled and deallocate them using a managed identity. Restrict its subscription scope and grant only the permissions required to discover and deallocate the approved VMs.
In Azure PowerShell, authenticate with Connect-AzAccount -Identity, select the intended subscription and filter Get-AzVM results by the tag. Stop-AzVM without -StayProvisioned deallocates the VM.
Schedule the runbook, record failures and define who can approve exclusions. Start with a report-only run that lists matching resource IDs. Use tags to record an approved auto-shutdown schedule for the workload, following a Start/Stop VMs pattern. Review dependencies before applying it.
For 14 development VMs needed for 55 of 168 weekly hours, the theoretical reduction is about 67%. Applied to a US$6,000 monthly compute baseline, that is roughly US$4,036 gross. This is schedule arithmetic, not a UK price or guaranteed saving.
Match automation to the service
Eligible Azure SQL Database serverless configurations can pause compute after inactivity and resume when a connection arrives. Storage remains chargeable, and open sessions or unsupported configurations can prevent pausing.
For recurring discovery, use Resource Graph queries in an Azure Managed Grafana dashboard to identify orphaned resources. Setup requires the Monitoring Reader role on Grafana’s managed identity, scoped to the relevant subscription or management group.
Use Azure Policy to audit missing ownership tags. Set review dates and route findings to named owners; an unattended dashboard doesn’t retire anything.
Frequently Asked Questions
How can I find unused Azure resources?
Use Azure Resource Graph to find candidates such as unattached disks, public IP addresses and detached network interfaces. Check activity with Azure Monitor, review costs in Azure Cost Management and confirm ownership and dependencies before removal.
Does an unattached disk mean it is unused?
No. It may contain retained application data or support recovery, backup or maintenance work, and it can still incur storage charges. Confirm its purpose and retention requirements with the data owner before deleting it.
Does stopping a VM stop all charges?
A VM stopped inside its operating system can remain allocated and billed. Deallocating it stops VM compute charges, but disks, snapshots, backups and other retained resources can continue to incur charges.
Does removing an unused resource guarantee a lower bill?
No. Some resources, such as ordinary network interfaces and NSGs, don’t normally have standalone charges, while reservations and reserved capacity remain commitments after a VM stops. Check actual costs and retained resources to confirm the effect on your bill.
Make resource retirement a controlled process
Removing unused Azure resources requires evidence of purpose, dependency and cost, followed by an approved retirement decision. Discovery queries identify candidates; they do not establish that deletion is safe or that every associated charge will end.
Speak to our team about Microsoft Azure consultancy and support to review resource usage, cloud costs, permissions and recovery requirements together. We can help identify what to remove, what to resize and what needs continued ownership.




