Automating Cloud Hygiene: Reclaiming Unattached Managed Disks & Public IPs at Scale
Why deleting Azure VMs leaves expensive Premium SSDs burning $56,000 monthly, and how automated Azure Runbooks safely reclaimed orphaned assets.
βDeleting an Azure Virtual Machine does not automatically delete its associated Premium SSD managed disk or static Public IP address. Unattached resources linger silently in your resource groups, burning tens of thousands of dollars on your monthly invoice.β
In October 2023, in my current role as Associate Director, Cloud Architecture & AI, I led a comprehensive Cloud FinOps audit for a banking client across 40 enterprise Azure subscriptions.
The clientβs development teams and automated CI/CD pipelines deployed and decommissioned hundreds of Azure Virtual Machines and AKS Kubernetes worker nodes every month.
The infrastructure team assumed that when a VM was deleted, Azure cleaned up all associated resources.
They were wrong.
The Default Behavior Trap
In Azure, a Virtual Machine, its Managed Disks, its Network Interfaces (NICs), and its Public IP addresses are separate resource providers.
When an engineer clicks βDeleteβ on an Azure VM in the portal or runs az vm delete, Azure deletes the VM compute shellβbut leaves the underlying Managed Disks (DiskState = Unattached) and Public IPs (IpAddress = Unattached) untouched.
Unless explicit cascading deletion rules are configured during VM creation, every decommissioned VM leaves an expensive storage footprint behind.
Our FinOps audit ran a cross-subscription query to inventory unattached resources.
The results were staggering:
# Azure CLI Inventory Query for Unattached Managed Disks
az graph query -q "Resources | where type =~ 'microsoft.compute/disks' and properties.diskState =~ 'Unattached'"
# Output: Found 420 Unattached Managed Disks (P30 1TB Premium SSDs)
# Output: Found 180 Unattached Static Public IP Addresses
A 1TB Premium SSD (P30 disk) costs approximately $135 per month in Azure, whether it is attached to an active VM or sitting 100% idle in Unattached state.
420 unattached 1TB Premium SSDs were generating a silent, wasted charge of $56,700 USD per month ($680,400 USD per year)!
The clientβs finance department had been paying this invoice for 14 months without realizing that half a million dollars was being burned on orphaned disks.
The Mess: The Deleted Forensic Database Disk
When the FinOps audit revealed the $56,700 monthly loss, an eager junior cloud engineer wrote a simple Bash script to clean up the environment:
# The dangerous immediate deletion script:
az disk delete --ids $(az disk list --query "[?managedBy==null && diskState=='Unattached'].id" -o tsv) --yes
He executed the script on a Tuesday afternoon.
Two hours later, an emergency P1 ticket was raised by the lead database administrator.
The DBA had intentionally detached a 2TB production SQL Server database disk from an offline VM earlier that morning to execute a manual forensic database repair.
Because the disk was temporarily in Unattached state while the DBA prepared his recovery commands, the junior engineerβs script scanned the disk, identified it as βunattached,β and deleted it permanently from Azure!
The database team spent 12 hours restoring the database from secondary backups.
Immediate deletion scripts without safety protocols were an operational hazard. We needed automated cloud hygiene with strict safety guardrails.
The Solution: The 7-Day Quarantine & Snapshot Runbook
We replaced manual deletion scripts with an automated Azure Automation Runbook executing PowerShell and Azure CLI scripts on a weekly schedule.
# Automated 4-Step Asset Reclamation Pipeline
1. **Identification & Snapshot:** Identify disks in `Unattached` state for >7 days. Automatically take a low-cost Standard LRS snapshot of the disk.
2. **Quarantine Tagging:** Apply tag `PendingDeletion = True` and `QuarantineDate = <Date>` to the unattached disk.
3. **Owner Notification:** Send an automated Teams/Slack notification and email to the Resource Group owner listing tagged disks.
4. **Automated Purge:** If the disk remains in `Unattached` state with `PendingDeletion = True` for 7 days after tagging, execute hard deletion automatically.
# Azure Automation PowerShell Runbook Snippet
$UnattachedDisks = Get-AzDisk | Where-Object { $_.ManagedBy -eq $null -and $_.DiskState -eq "Unattached" }
foreach ($Disk in $UnattachedDisks) {
$QuarantineDate = (Get-Date).ToString("yyyy-MM-dd")
# 1. Take a low-cost safety snapshot before tagging
New-AzSnapshot -ResourceGroupName $Disk.ResourceGroupName -SnapshotName "$($Disk.Name)-SafetySnap" -Snapshot (New-AzSnapshotConfig -Location $Disk.Location -CreateOption Copy -SourceResourceId $Disk.Id)
# 2. Tag disk with Quarantine metadata
$Tags = $Disk.Tags
if ($Tags -eq $null) { $Tags = @{} }
$Tags["PendingDeletion"] = "True"
$Tags["QuarantineDate"] = $QuarantineDate
Set-AzDisk -ResourceGroupName $Disk.ResourceGroupName -DiskName $Disk.Name -Tag $Tags
Write-Output "Quarantined Disk: $($Disk.Name) in RG: $($Disk.ResourceGroupName)"
}
If a DBA detaches a disk for manual maintenance, he has a 7-day safety window to remove the PendingDeletion tag or re-attach the disk before any deletion occurs, backed by an automated recovery snapshot.
The Impact
- $56,700 Monthly Savings: Reclaimed $56,700 per month ($680,000/year) in wasted unattached disk and Public IP storage spend.
- Zero Data Loss: Safety snapshots and 7-day quarantine tagging guaranteed 100% protection against accidental disk deletions.
- Automated Cloud Hygiene: Built a self-sustaining Azure Automation Runbook that keeps subscriptions 100% clean of orphaned cloud waste.
Key Takeaway
Deploy Automated Scheduled Cleanup Runbooks for Orphaned Cloud Assets.
Never run immediate bulk deletion scripts against unattached cloud disks. Deploy an Azure Automation Runbook that takes low-cost safety snapshots, applies a 7-day Quarantine Tagging Protocol, and notifies resource owners via automated webhooks before executing hard deletions to reclaim unattached disk and IP waste safely.
Architecture and decisions: mine. Debugging sessions at odd hours: mine. AI assistance: structure, syntax, first draft. β Sachin
Sachin Kumar Sharma
Associate Director (Infrastructure & Cloud Architecture Strategy) | 20+ Yrs Exp
Architecting resilient multi-cloud enterprise landing zones, SDN overlay fabrics, DevSecFinOps automation pipelines, and autonomous Agentic AI platforms.
π‘ Related Engineering Articles
Observability on a Budget: Optimizing Cloud Log Ingestion Costs
How we cut an enterprise Azure Log Analytics and SIEM bill by 40% using Edge Data Collection Rules, KQL telemetry tiering, and health-probe filtering.
Azure DevSecFinOps: Automating Governance at Scale
How we embedded Checkov security scanning and Infracost financial guardrails directly into GitHub Actions to block unapproved $28,000 cloud bills before merge.
The Azure ExpressRoute BGP Steering Incident: 3 Weeks of Asymmetric Drops
How a missing local-pref in Terraform caused a Β£40,000 asymmetric routing loop across dual 10G ExpressRoute links, and how Checkov pipeline rules now prevent it.
π¬ Stay Updated on Tech Releases
Sign up to get notified when I publish new production war stories, agentic AI architecture blueprints, or open-source infrastructure tools.