Stop paying for unused Azure resources. In this episode of M365.fm
, we explore how to build an automated Azure Cleanup Engine that helps organizations identify and remove wasted cloud spend before it becomes a budgeting problem.
We discuss the hidden costs of forgotten virtual machines, unattached disks, stale snapshots, abandoned test environments, unused networking components, and other orphaned Azure resources that silently increase monthly bills. The episode walks through practical strategies for continuously detecting and cleaning up these resources using Azure-native automation and governance tools.
You’ll learn how to use Azure Automation, Azure Functions, Azure Resource Graph, Logic Apps, tagging strategies, and Azure Policy to create a scalable and safe cleanup process. We also cover approval workflows, lifecycle management, reporting, and governance best practices to ensure automation does not impact production workloads.
The episode includes real-world examples, common optimization mistakes, and practical recommendations for improving visibility, reducing operational overhead, and building a more cost-efficient Azure environment.
Whether you are an Azure administrator, cloud architect, FinOps professional, or IT leader, this episode provides actionable guidance to help you automate Azure hygiene and stop paying for resources nobody uses.
Imagine you log into your azure portal and see dozens of forgotten resources, each quietly adding to your monthly bill. Many organizations face this issue, with cloud waste accounting for up to 35% of total spending because of idle servers and unused assets. You might not realize it, but automating your clean-up process can change everything. With Automated Azure Cleanup, you gain lifecycle control and accountability. Some companies have saved over $420,000 each year by letting automation handle clean-up instead of relying on manual checks.
Key Takeaways
- Automating Azure cleanup can save organizations significant costs, with some reporting savings of over $420,000 annually.
- Manual cleanup processes are time-consuming and prone to errors, leading to security risks and increased cloud expenses.
- Automation enhances compliance by ensuring resources adhere to established policies without constant manual checks.
- Implementing a strong tagging strategy is crucial for identifying and managing resources effectively during cleanup.
- Using Azure tools like Logic Apps and PowerShell scripts can streamline the discovery and removal of unused resources.
- Regular audits and monitoring of resources help maintain an organized and cost-effective cloud environment.
- Establishing approval workflows for resource deletions adds a layer of safety, preventing accidental loss of critical assets.
- Testing and validating your automated cleanup processes ensures they function correctly and protect important data.
Automated Azure Cleanup Overview

Why Automate Azure Cleanup?
You may find that managing cloud resources by hand creates many challenges. When you try to clean-up unused assets manually, you risk missing important steps. This can lead to security problems and compliance issues. You might leave behind data remnants, orphaned configurations, or stale credentials. These leftovers can create long-term risks for your organization.
Manual clean-up also takes a lot of time and effort. You may spend hours tracking down abandoned resources or unmonitored environments. This process drains your team's energy and increases your cloud costs. Automation helps you avoid these problems. When you automate azure cleanup, you save money and free up your team for more important work.
Here are some common challenges with manual clean-up:
- Improper resource decommissioning can lead to security exposure.
- Data remnants and stale credentials create risks.
- Manual processes consume time and cloud budgets.
- Hidden costs can build up from unmonitored resources.
- Scaling your infrastructure becomes difficult without automation.
Key Benefits for Organizations
Automated azure cleanup brings many advantages to your organization. You gain better control over your resources and reduce human error. Automation makes sure that your resources follow the rules you set, without needing constant checks.
Some of the main benefits include:
- Streamlined compliance processes that keep your resources in line with standards.
- Reduced human error, since automation handles policy enforcement.
- Centralized management, which gives you a clear view of your resource landscape.
You can also see real savings. Many organizations report cost reductions of up to 40% by using automated azure cleanup. Some companies save between 22% and 35% over a year. Even short optimization efforts can cut expenses by 10% in just two weeks. These savings add up quickly and help your business grow.
"Another major benefit of this process was establishing much stronger governance of compute resources across the entire organization."
"Now, with clearer ownership, clearer accountability, and better inventory, it’s a much better experience."
"Improving our governance has definitely made securing our environment easier."
How the Automated Azure Cleanup Engine Works
The Automated Azure Cleanup Engine from M365.fm gives you a simple way to automate the cleanup of unused resources. This engine uses Azure Policy, intelligent tagging, and Logic Apps to manage your cloud environment. You set the rules with Azure Policy. Tags provide context about each resource. Logic Apps carry out the clean-up actions.
This system shifts you from a manual, reactive approach to a proactive, automated azure cleanup strategy. The engine continuously checks your environment, finds resources that no longer serve a purpose, and removes them before they become a financial burden. You gain lifecycle control, accountability, and visibility into your cloud spending.
When you automate the cleanup process, you make sure that only necessary resources stay active. You can measure reclaimed and prevented costs, which helps you prove the value of your efforts. With automated azure cleanup, you can focus on innovation while your cloud stays efficient and secure.
Prerequisites for Automatic Clean-Up
Before you automate the removal of unused resources in Azure, you need to set up the right permissions, tools, and tagging strategy. These steps help you avoid mistakes and make sure your clean-up engine works as expected.
Required Azure Permissions
You must have the right permissions to delete deployments and manage resources. The most important permission is the ability to perform the Microsoft.Resources/deployments/delete action. This lets you remove deployments that are no longer needed. You should also consider these roles:
- Resource Policy Contributor: Handles most Azure Policy operations.
- Owner: Grants full rights to manage and delete resources.
- Contributor: Allows you to read and trigger resource remediation.
- Reader: Lets you view all resources.
- User Access Administrator: Assigns permissions for deployments.
Security teams need visibility across all assets. Assign permissions at the smallest effective scope. Use built-in roles from Azure RBAC and limit custom roles. Always verify permissions to keep your environment secure.
Tools and Modules
You need the right tools to automate clean-up tasks. The latest azure powershell module is essential for scripting and automation. You should also use the Azure CLI and Resource Graph for advanced queries and reporting.
PowerShell, CLI, and Resource Graph
The azure powershell module helps you loop through subscriptions and resource groups. It can identify role assignments with an object type of 'Unknown' and remove them. If you do not have the latest azure powershell module, install it before you start. The latest azure powershell module supports automation tasks and works well with custom modules and internal cmdlets. You can also use Python modules for scripting in Azure Automation.
| Module Type | Description |
|---|---|
| Azure PowerShell Az modules | Essential for Azure automation tasks. |
| Internal Cmdlets | Used for asset management in Azure. |
| Python Modules | Available for scripting in Azure Automation. |
| Custom Modules | User-defined modules for specific needs. |
Azure Policy and Logic Apps
Azure Policy lets you set rules for your resources. Logic Apps help you automate actions, such as deleting unattached disks or cleaning up unused resources. You can use a powershell script inside Logic Apps to trigger clean-up workflows.
Tagging Strategy
A strong tagging strategy improves the accuracy of your automated clean-up. Intelligent tagging helps you identify temporary or unattached resources for deletion. It also tracks creation and expiration dates, which prevents resource sprawl.
Follow these steps for effective tagging:
- Define a mandatory tagging policy with keys for ownership, cost center, and environment.
- Use Azure Policy to enforce your tagging standard.
- Audit all resources to find and fix tagging gaps.
- Add tagging requirements to your Infrastructure as Code templates.
- Review your tagging policy regularly to keep it relevant.
Automated tagging can be set up with Logic Apps or Azure Automation runbooks. Regular audits and Azure Policy enforcement keep your tags accurate and useful.
Tip: Start with essential tags and keep your tagging rules simple. This makes it easier to manage and scale your clean-up engine.
Identify Unused Resources
Finding unused resources is a key step in any successful clean-up process. You need to know what is no longer needed before you can remove it. Azure gives you several tools and methods to help you discover these resources quickly and accurately.
Using Tags and Policies
Tags and policies help you manage your resources by adding important information. You can use tags to track who owns a resource and when it should be reviewed. This makes it easier to spot unused resources during regular audits. Azure Policy enforces tagging rules, so every resource has the right tags. When you use both tags and policies, you improve your ability to find resources that are ready for clean-up. This approach also helps you keep your environment organized and under control.
Tip: Always include tags for ownership and review dates. This makes future audits much easier and helps you avoid missing unused resources.
Resource Graph Queries
Azure resource graph queries give you a powerful way to search across your environment. You can use these queries to find resources that are not connected or in use. For example, you can look for orphaned disks, public IP addresses, network security groups, or network interfaces that are not attached to anything. These items often become unused resources after projects end or systems change.
Here are some best practices for using azure resource graph queries:
- Identify managed disks that are not attached to any virtual machine.
- Find public IP addresses not linked to any network interface or load balancer.
- Locate network security groups not associated with any network interface or subnet.
- Search for network interfaces not connected to any virtual machine or private endpoint.
You can run these queries in the Azure portal or automate them as part of your clean-up engine.
Custom Scripts for Discovery
You can also use custom scripts to automate the discovery of unused resources. Many teams write scripts using KQL (Kusto Query Language) to search for orphaned or idle services. PowerShell cmdlets offer another way to scan your environment and report on what is no longer needed. You can find helpful scripts in public repositories, such as GitHub, and adapt them for your own needs.
Here is a simple example of a PowerShell script to list unattached disks:
Get-AzDisk | Where-Object { -not $_.ManagedBy }
By running scripts like this on a schedule, you make sure your clean-up process stays up to date. Automation tools, such as Azure Automation runbooks, can help you run these scripts regularly and send you reports.
Note: Using automation for discovery saves you time and reduces the risk of missing unused resources.
Automating Disk Cleanup in Azure
Unattached Disk Detection
You may not realize how many disks in your environment are no longer attached to any virtual machine. These unattached disks often remain after you delete VMs or make changes to your infrastructure. Over time, they can add up and increase your cloud costs. Studies show that unattached disks account for 15% of cloud waste. This means a significant portion of your Azure disks may be eligible for clean-up.
To find unattached disks, you can use Azure Resource Graph or PowerShell scripts. These tools help you scan your environment and identify disks that are not in use. You should check for disks that have not been updated or accessed recently. By focusing on these disks, you can target the resources most likely to be waste.
Tip: Schedule regular reviews of your disk inventory. This helps you catch unused disks before they become a financial burden.
PowerShell Automation
Automating disk cleanup becomes much easier when you use PowerShell. With PowerShell, you can quickly find unattached disks and filter them by their last modified date. For example, you can identify disks that have not changed in over 60 days. This approach helps you focus on disks that are truly idle.
PowerShell automation streamlines the process in several ways:
- You can identify unattached disks that have not been updated in a long time.
- The scripts optimize your resource usage by removing unnecessary disks.
- You reduce costs linked to unused resources.
Here is a sample PowerShell script to list unattached disks older than 60 days:
$cutoffDate = (Get-Date).AddDays(-60)
Get-AzDisk | Where-Object {
-not $_.ManagedBy -and $_.TimeCreated -lt $cutoffDate
}
You can adapt this script to fit your needs. Run it as part of your regular maintenance to keep your environment clean.
Scheduling Disk Cleanup
You should not rely on manual checks to keep your disks tidy. Instead, set up a schedule for automating disk cleanup. Use Azure Automation Accounts or Logic Apps to run your PowerShell scripts at regular intervals. This ensures that you catch unused disks before they create unnecessary costs.
Automating the disk deletion process also improves your governance. You can track which disks were deleted and when. This adds accountability and helps you measure the impact of your clean-up efforts. Regular scheduling keeps your Azure environment efficient and prevents cloud waste from building up.
Note: Always review your deletion policies and keep backups if needed. This protects you from accidental data loss.
By following these steps, you can maintain a healthy cloud environment and control your spending.
Automated Resource Group Cleanup
Cleaning up unused resource groups in Azure helps you keep your environment organized and cost-effective. You can use automated resource group cleanup to remove groups that no longer serve a purpose. This process relies on smart tagging, age and usage analysis, and approval workflows to ensure you only delete what you truly do not need.
Tag-Based Group Cleanup
Tags give you a simple way to track and manage your resource groups. When you apply tags like "owner," "environment," or "expiration date," you make it easier to identify which groups need attention. For example, you can tag temporary projects with a "delete-after" date. When that date passes, your cleanup engine can flag the group for review or removal.
You should enforce tagging policies across your Azure environment. Azure Policy can help you make sure every resource group has the right tags. This step improves your ability to automate clean-up and reduces the risk of deleting important resources by mistake. Regular audits of your tags keep your system accurate and up to date.
Tip: Use clear and consistent tag names. This makes automated processes more reliable and easier to manage.
Age and Usage Patterns
You can decide which resource groups to clean up by looking at their age and how they are used. Many organizations set rules based on how old a group is, whether it has recent activity, or if it has a special tag that marks it as persistent. The table below shows common criteria for resource group cleanup:
| Criteria Type | Description |
|---|---|
| Age | Resource groups older than a specified age are identified for cleanup. |
| Usage Patterns | Resources lacking a 'persistent' tag or showing no recent activity are flagged for removal. |
| Expiration Tags | Resources with a 'delete-after' tag are considered for cleanup based on their expiration date. |
| Cost | Resource groups with significant spending but no recent activity tags are also targeted. |
By using these criteria, you can focus your efforts on groups that are most likely to be unused. This approach helps you save money and keep your Azure environment tidy.
Approval Workflows
Before you delete a resource group, you may want to get approval from the owner or another team member. Approval workflows add a layer of safety to your automated resource group cleanup process. You can set up an approval workflow in Azure using Logic Apps. Here is a simple way to do it:
- Create a new Logic App in the Azure portal.
- Start with a blank Logic App and add an HTTP trigger.
- Add an approval email step and connect it to your Office 365 account.
- Create a condition to determine whether to delete the resource group or do nothing.
- In the true branch, add a step to delete the resource group.
- Test the Logic App using an API testing tool like Postman by sending a JSON body with the resource group name.
- Upon approval, the Logic App will delete the specified resource group.
This workflow ensures that you do not remove important resources by accident. You keep control over your environment while still benefiting from automation.
Note: Always document your approval process. This helps you track decisions and improves accountability.
Automate Azure Cleanup Execution
Logic Apps and Automation Accounts
You can automate your resource management in azure by combining Logic Apps and Automation Accounts. Logic Apps help you create workflows that respond to events or run on a schedule. Automation Accounts let you run scripts and manage resources without manual effort. When you use both, you build a powerful system for handling clean-up tasks.
The process often follows these steps:
| Step | Description |
|---|---|
| 1 | Logic App triggers on JSON upload or timer to detect unused resources. |
| 2 | Sends approval requests via Microsoft Teams using Adaptive Cards. |
| 3 | Upon approval, triggers Azure Automation Runbook to delete specified resources. |
| 4 | Logs all actions to Azure Log Analytics for auditing and alerts. |
This approach gives you control and flexibility. You can set up triggers based on your needs. For example, you might start a workflow when someone uploads a file or at a certain time each week. The approval step adds safety, so you do not delete important resources by mistake. Every action gets logged, which helps you track changes and stay compliant.
Scheduling and Monitoring
You need to schedule your automation tasks to keep your environment clean and efficient. Good scheduling ensures that your clean-up jobs run at the right time and do not overload your system. Monitoring helps you catch problems early and make sure everything works as planned.
Best practices for scheduling and monitoring include:
- Ensure background tasks can restart automatically and handle demand peaks by allocating sufficient resources and implementing a queueing mechanism.
- Divide complex tasks into smaller, reusable steps to enhance efficiency and flexibility.
- Implement orchestration logic to manage the execution of task steps, including handling timeouts and tracking progress.
- Design tasks to recover gracefully from failures, including checkpointing to save job state.
- Monitor job completion and alert on missed schedules to ensure tasks are running as expected.
You can use azure tools like Automation Accounts and Logic Apps to set up these schedules. Alerts and dashboards help you see when jobs finish or if something goes wrong. By breaking big jobs into smaller steps, you make your system more reliable and easier to manage.
Logging and Audit Trails
Logging and audit trails play a key role in keeping your automated processes accountable. You need to know what actions took place, who approved them, and when they happened. This information helps you meet compliance standards and investigate any issues.
Microsoft engages in continuous security monitoring of its systems to detect and respond to threats. Key principles include robustness, accuracy, and speed, which are essential for catching attackers and ensuring accountability.
To build strong logging and audit trails, follow these steps:
- Enable Comprehensive Logs & Retention: Ensure logs are enabled for all resources and stored in Azure Monitor or Log Analytics to detect suspicious activities.
- Correlate Events: Use Azure security audit logs to correlate events across different subscriptions or microservices, enhancing accountability.
- Adjust Retention Periods: Regularly adjust log retention periods to satisfy compliance while capturing all infiltration footprints.
You should review your logs often. Look for patterns or unusual activity. Adjust your retention settings to match your company’s policies. Good logging makes it easier to prove that your clean-up process works and keeps your azure environment secure.
Best Practices for Automatic Clean-Up
Testing and Validation
You should always test your automated resource cleanup process before using it in your live environment. Start by running your clean-up script in a test subscription or with non-critical cloud resources. This helps you catch errors and see how the process works. Use azure powershell scripts to simulate deletions and check the results. Testing lets you confirm that your automatic clean-up engine only removes what you want.
After testing, validate the results. Review logs and reports to make sure the right resources were deleted. If you find mistakes, adjust your scripts or policies. Repeat this process until you feel confident. Testing and validation protect your important data and improve operational efficiency.
Tip: Schedule a weekly automated cleanup in your test environment to spot issues early.
Exclusions and Rollback
Not every resource should be deleted. You need to set up exclusions for critical systems or resources with special roles. Use tags like "DoNotDelete" or "Critical" to mark these items. Azure Policy can help enforce these exclusions. This step keeps your business running smoothly and avoids accidental loss.
Sometimes, you may need to undo a resource cleanup action. Always plan for rollback. Keep backups or snapshots of important data before running your automated resource cleanup. Document your rollback steps and make sure your team knows how to use them. A good rollback plan gives you peace of mind and helps you recover quickly if something goes wrong.
| Exclusion Type | Tag Example | Description |
|---|---|---|
| Critical | DoNotDelete | Protects vital cloud resources |
| Compliance | AuditKeep | Keeps resources for audits |
| Temporary | TempExclude | Skips short-term exclusions |
Measuring Cost Savings
You want to see the value of your optimization efforts. Start by using Azure Cost Management dashboards to monitor spending. Set budgets and alerts at the subscription or resource-group level. These tools help you spot cost spikes and track the impact of your resource cleanup.
You can also use Azure Advisor to find over-provisioned VMs and idle resources. This helps you optimize resource usage and improve cost optimization. To measure your progress, track key metrics and KPIs. Review budget adherence and resource utilization each month. Many organizations use chargeback or showback practices to encourage teams to manage their own costs.
- Monitor costs with dashboards or third-party tools.
- Set budgets and automated alerts for quick response.
- Use native recommendations to find savings opportunities.
- Track metrics that show cost efficiency and business value.
- Review budget and usage metrics regularly.
- Motivate teams to optimize their own usage.
Note: Regular measurement helps you prove the value of automated resource cleanup and supports better management decisions.
You can take control of your cloud environment by automating resource cleanup. The Automated Azure Cleanup Engine helps you save money, improve accountability, and manage resource lifecycles with ease. When you automate cleanup in azure, you reduce waste and boost efficiency. Start measuring your results today. Explore M365.fm’s solution or use these steps to build your own engine for better cloud governance.
FAQ
What is the Automated Azure Cleanup Engine?
You use the Automated Azure Cleanup Engine to remove unused resources in your cloud. This tool works with microsoft services like Azure Policy, Logic Apps, and Resource Graph. You gain control over your environment and reduce costs with this engine.
How does tagging help with resource cleanup?
Tagging helps you organize and identify resources. When you use microsoft tagging standards, you can track ownership, expiration, and purpose. This makes it easier to find and remove unused items. You keep your environment clean and efficient.
Can I automate cleanup for all resource types?
You can automate cleanup for most resource types in microsoft Azure. Some resources may need special handling. Always review microsoft documentation for exceptions. Automation works best when you follow tagging and policy guidelines.
How do I schedule cleanup tasks?
You schedule cleanup tasks using microsoft Logic Apps or Automation Accounts. These tools let you run scripts at set times. You can set up daily, weekly, or monthly cleanups. Scheduling keeps your environment tidy without manual effort.
What permissions do I need for automated cleanup?
You need the right permissions in your microsoft Azure account. Roles like Owner, Contributor, and Resource Policy Contributor allow you to manage and delete resources. Always check microsoft RBAC settings before starting automation.
How do I track deleted resources?
You track deleted resources using microsoft logging and audit trails. Store logs in Azure Monitor or Log Analytics. Review logs often to see what was removed and when. This helps you stay compliant with microsoft security standards.
Is automated cleanup safe for production environments?
Automated cleanup is safe when you test it first. Use a test environment before running scripts in production. Follow microsoft best practices for exclusions and rollback. Always protect critical resources with tags and review your policies.
🚀 Want to be part of m365.fm?
Then stop just listening… and start showing up.
👉 Connect with me on LinkedIn and let’s make something happen:
- 🎙️ Be a podcast guest and share your story
- 🎧 Host your own episode (yes, seriously)
- 💡 Pitch topics the community actually wants to hear
- 🌍 Build your personal brand in the Microsoft 365 space
This isn’t just a podcast — it’s a platform for people who take action.
🔥 Most people wait. The best ones don’t.
👉 Connect with me on LinkedIn and send me a message:
"I want in"
Let’s build something awesome 👊
1
00:00:00,000 --> 00:00:04,560
Azure says a very simple promise you pay for what you use, but in reality most teams aren't
2
00:00:04,560 --> 00:00:06,080
paying for what they use.
3
00:00:06,080 --> 00:00:10,840
They are paying for what nobody shutdown, what nobody claimed, and what nobody even remembers
4
00:00:10,840 --> 00:00:11,840
is still running.
5
00:00:11,840 --> 00:00:16,480
An idle VM keeps billing, and often to disk keeps billing, a stale test stack keeps billing,
6
00:00:16,480 --> 00:00:20,280
even a forgotten workflow piece adds to the cost because the meter doesn't care if your
7
00:00:20,280 --> 00:00:21,280
project ended.
8
00:00:21,280 --> 00:00:23,520
It only cares that the resource still exists.
9
00:00:23,520 --> 00:00:25,320
And this is where manual governance breaks.
10
00:00:25,320 --> 00:00:27,480
Cleanup depends on memory, it depends on spare time.
11
00:00:27,480 --> 00:00:31,320
It depends on someone noticing a report after the spend has already landed.
12
00:00:31,320 --> 00:00:35,600
Then the meeting starts, finances the number, engineering checks all tickets, everyone tries
13
00:00:35,600 --> 00:00:39,600
to figure out who owns the mess that model doesn't scale.
14
00:00:39,600 --> 00:00:42,000
So in this episode we are building a different one.
15
00:00:42,000 --> 00:00:46,720
As your policy sets the rules, tags carry the context and logic apps turns that context
16
00:00:46,720 --> 00:00:47,800
into action.
17
00:00:47,800 --> 00:00:52,640
The result is a cleanup engine that finds resources with no valid reason to live and removes
18
00:00:52,640 --> 00:00:53,840
them safely.
19
00:00:53,840 --> 00:00:57,200
Because if governance stays manual, waste scales faster than the team.
20
00:00:57,200 --> 00:00:59,160
Why cloud waste keeps surviving?
21
00:00:59,160 --> 00:01:01,440
Most people treat cloud waste like a sizing problem.
22
00:01:01,440 --> 00:01:05,360
They think a VM is too big or a database tier is too high or a storage setting costs more
23
00:01:05,360 --> 00:01:06,360
than it should.
24
00:01:06,360 --> 00:01:08,400
While those things are real, they aren't the full pattern.
25
00:01:08,400 --> 00:01:11,920
A lot of cloud waste survives for a much simpler reason.
26
00:01:11,920 --> 00:01:14,960
Resources keep living long after the work that created them is gone.
27
00:01:14,960 --> 00:01:17,520
That is, life cycle drift.
28
00:01:17,520 --> 00:01:20,640
A project starts fast because the cloud makes starting easy.
29
00:01:20,640 --> 00:01:24,440
A dev team spins up a sandbox or someone runs a proof of concept or a temporary integration
30
00:01:24,440 --> 00:01:26,240
gets built to test an idea.
31
00:01:26,240 --> 00:01:28,320
Then priorities shift and the sprint ends.
32
00:01:28,320 --> 00:01:30,600
The owner changes or the team moves on.
33
00:01:30,600 --> 00:01:32,880
The work stops, but the resources do not.
34
00:01:32,880 --> 00:01:37,160
And because the cloud is good at staying available, it is also very good at staying expensive.
35
00:01:37,160 --> 00:01:39,360
What typically happens is this, the ticket closes.
36
00:01:39,360 --> 00:01:41,800
The engineer who built the environment joins another team.
37
00:01:41,800 --> 00:01:44,440
The manager assumes the cost belongs somewhere else.
38
00:01:44,440 --> 00:01:46,760
Finance sees the spend, but they don't see the intent.
39
00:01:46,760 --> 00:01:48,000
The environment just sits there.
40
00:01:48,000 --> 00:01:51,480
Each month it looks less like an active decision and more like background noise.
41
00:01:51,480 --> 00:01:53,280
That noise grows when tagging is weak.
42
00:01:53,280 --> 00:01:58,160
If a resource has no clear owner, no environment tag and no expiry date, then your cost data
43
00:01:58,160 --> 00:01:59,160
loses its shape.
44
00:01:59,160 --> 00:02:01,680
You can see the bill, but you can't see the story behind the bill.
45
00:02:01,680 --> 00:02:03,960
This is why untagged spend matters so much.
46
00:02:03,960 --> 00:02:08,520
When tagging discipline is poor, industry patterns show that 20 to 30% of cloud spend often
47
00:02:08,520 --> 00:02:10,320
falls into unallocated territory.
48
00:02:10,320 --> 00:02:13,360
It isn't hidden from Azure, but it is hidden from accountability.
49
00:02:13,360 --> 00:02:16,480
And once accountability gets blurry, clean up slows down.
50
00:02:16,480 --> 00:02:19,560
Manual review sounds responsible, but it creates a massive delay loop.
51
00:02:19,560 --> 00:02:23,920
On exports a report, another person filters by service and a team lead asks engineers if
52
00:02:23,920 --> 00:02:25,440
anything can be removed.
53
00:02:25,440 --> 00:02:28,160
People reply late because they are busy doing actual delivery work.
54
00:02:28,160 --> 00:02:32,640
A week passes or maybe two, and during that time nothing changes except the bill.
55
00:02:32,640 --> 00:02:35,160
Delay protects waste.
56
00:02:35,160 --> 00:02:38,520
Engineers are usually great at optimizing the things they are actively building.
57
00:02:38,520 --> 00:02:41,640
They care about performance, deployment speed and reliability.
58
00:02:41,640 --> 00:02:44,960
But almost nobody wakes up excited to hunt for a forgotten sandbox from three sprints
59
00:02:44,960 --> 00:02:45,960
ago.
60
00:02:45,960 --> 00:02:49,240
That work has no momentum and no visible product outcome, so it slips.
61
00:02:49,240 --> 00:02:51,600
In one level deeper, this isn't really a tooling failure.
62
00:02:51,600 --> 00:02:54,840
Azure already gives you policy, resource graph and cost management.
63
00:02:54,840 --> 00:02:57,800
The platform isn't missing controls, the model is missing enforcement.
64
00:02:57,800 --> 00:03:02,080
In most organizations, governance still sits outside the delivery path, teams build first,
65
00:03:02,080 --> 00:03:03,800
and then governance inspects later.
66
00:03:03,800 --> 00:03:06,640
But by the time later arrives, the waste already exists.
67
00:03:06,640 --> 00:03:08,160
The issue isn't that people don't care.
68
00:03:08,160 --> 00:03:12,280
The issue is that the system asks people to remember life cycle decisions in an environment
69
00:03:12,280 --> 00:03:13,680
built for speed.
70
00:03:13,680 --> 00:03:14,920
That assumption is broken.
71
00:03:14,920 --> 00:03:17,720
What works better is a control model that starts earlier.
72
00:03:17,720 --> 00:03:21,960
You need a system that captures intent when resources are created, keeps that intent attached
73
00:03:21,960 --> 00:03:26,120
through tags and checks continuously whether the resource still deserves to exist.
74
00:03:26,120 --> 00:03:29,000
Once you see that, the next question isn't who forgot the cleanup.
75
00:03:29,000 --> 00:03:31,800
It's what the engine needs to decide for them.
76
00:03:31,800 --> 00:03:33,480
The governance model behind the engine.
77
00:03:33,480 --> 00:03:35,480
So what does this engine actually need to be?
78
00:03:35,480 --> 00:03:36,480
Keep it simple.
79
00:03:36,480 --> 00:03:37,480
You only need three parts.
80
00:03:37,480 --> 00:03:38,480
Policy is the law.
81
00:03:38,480 --> 00:03:39,480
Tags are the context.
82
00:03:39,480 --> 00:03:40,920
Logic apps are the action.
83
00:03:40,920 --> 00:03:45,200
That distinction matters because most governance designs fail by mixing all three together.
84
00:03:45,200 --> 00:03:49,160
They try to make policy decide every outcome or they turn automation into a massive script
85
00:03:49,160 --> 00:03:54,240
full of hard coded exceptions or they let tags grow into a messy dictionary that nobody trusts.
86
00:03:54,240 --> 00:03:58,520
When that happens, the system becomes impossible to explain, difficult to maintain, and very
87
00:03:58,520 --> 00:04:00,640
easy to bypass the moment pressure goes up.
88
00:04:00,640 --> 00:04:02,320
It starts with policy.
89
00:04:02,320 --> 00:04:06,600
Policy decides what metadata must exist, where it must live, and how it should be inherited.
90
00:04:06,600 --> 00:04:08,000
It isn't the cleanup engine itself.
91
00:04:08,000 --> 00:04:10,880
It is the rule layer that makes the cleanup engine possible.
92
00:04:10,880 --> 00:04:15,880
In practice, this means policy checks if resources carry the required tags, ensures those tags
93
00:04:15,880 --> 00:04:19,720
come from the resource group when they should, and stops new deployments from proceeding
94
00:04:19,720 --> 00:04:21,800
without the minimum context attached.
95
00:04:21,800 --> 00:04:24,120
The sequence of how you roll this out is everything.
96
00:04:24,120 --> 00:04:27,400
Audit first, then modify, then deny.
97
00:04:27,400 --> 00:04:30,920
Audit gives you visibility without breaking teams on day one, which is useful because most
98
00:04:30,920 --> 00:04:35,400
of the states already contain years of drift that you can't fix overnight.
99
00:04:35,400 --> 00:04:38,880
Modify lets you remediate those existing apps through remediation tasks and inherited
100
00:04:38,880 --> 00:04:43,360
values, and then deny, comes much later, once people know the contract and the deployment
101
00:04:43,360 --> 00:04:45,040
path is ready for enforcement.
102
00:04:45,040 --> 00:04:47,960
You want to apply that model high in the hierarchy.
103
00:04:47,960 --> 00:04:52,040
Management group scope comes first, because subscription by subscription governance falls
104
00:04:52,040 --> 00:04:54,200
apart the moment the estate grows.
105
00:04:54,200 --> 00:04:55,880
Teams create their own variations.
106
00:04:55,880 --> 00:04:57,240
Owners change settings.
107
00:04:57,240 --> 00:05:00,720
One subscription gets a stricter policy set while another gets left behind and soon your
108
00:05:00,720 --> 00:05:04,560
control model depends on local habits instead of shared standards.
109
00:05:04,560 --> 00:05:09,440
A management group assignment gives you one operating rule that flows downward to everything.
110
00:05:09,440 --> 00:05:12,240
Inside the subscription, resource groups do the heavy lifting.
111
00:05:12,240 --> 00:05:16,000
This clicked for me when I stopped thinking about resource groups as folders and started
112
00:05:16,000 --> 00:05:18,200
treating them as life cycle boundaries.
113
00:05:18,200 --> 00:05:22,040
This is where most resources share the same owner, the same environment, the same cost
114
00:05:22,040 --> 00:05:25,080
center, and usually the same retirement pattern.
115
00:05:25,080 --> 00:05:28,560
Inheritance from the resource group catches a large part of the estate without forcing every
116
00:05:28,560 --> 00:05:32,120
deployment team to tag every single child resource manually.
117
00:05:32,120 --> 00:05:34,360
There is one hard limit you have to keep in view.
118
00:05:34,360 --> 00:05:38,880
Azure policy can enforce rules within subscriptions, but it doesn't natively enforce tags at the
119
00:05:38,880 --> 00:05:41,200
exact moment a subscription is created.
120
00:05:41,200 --> 00:05:42,760
Don't design a fantasy system.
121
00:05:42,760 --> 00:05:44,440
Design the one Azure actually supports.
122
00:05:44,440 --> 00:05:48,720
Put subscriptions under the right management groups, apply your policy there, and use post-creation
123
00:05:48,720 --> 00:05:52,200
audit and automation to catch what the platform doesn't do at birth.
124
00:05:52,200 --> 00:05:53,720
And keep the tag model tight.
125
00:05:53,720 --> 00:05:57,520
Azure supports far more tags than you should ever use, just because you have the slots
126
00:05:57,520 --> 00:05:59,000
doesn't mean you should fill them.
127
00:05:59,000 --> 00:06:03,280
If the engine's purpose is safe cleanup, then your first tag set should focus on deletion
128
00:06:03,280 --> 00:06:05,800
decisions, ownership, and exceptions.
129
00:06:05,800 --> 00:06:09,320
Once teams trust the model, you can expand for reporting or broader governance.
130
00:06:09,320 --> 00:06:13,360
But if you start with 20 tags, people will find ways around the process before the engine
131
00:06:13,360 --> 00:06:15,040
ever earns its credibility.
132
00:06:15,040 --> 00:06:16,720
The model is small by design.
133
00:06:16,720 --> 00:06:18,240
Policy creates the contract.
134
00:06:18,240 --> 00:06:21,120
Resource groups spread that contract through inheritance.
135
00:06:21,120 --> 00:06:24,240
Management groups keep the contract consistent at scale.
136
00:06:24,240 --> 00:06:27,360
Logic apps then reads that structure and acts on it in a repeatable way.
137
00:06:27,360 --> 00:06:31,000
This isn't because automation is smarter than people, but because it is better at checking
138
00:06:31,000 --> 00:06:35,680
the same rule every single time without getting distracted by sprint pressure, team changes,
139
00:06:35,680 --> 00:06:40,160
or someone's half memory of why a resource was created six months ago.
140
00:06:40,160 --> 00:06:43,320
Now that the model is in place, the next part gets very practical.
141
00:06:43,320 --> 00:06:47,280
We need to look at which tags actually let the engine decide what can be deleted, what
142
00:06:47,280 --> 00:06:51,160
must be left alone, and what needs a human in the loop.
143
00:06:51,160 --> 00:06:53,520
The tagging system that makes deletion possible.
144
00:06:53,520 --> 00:06:57,680
Now we get to the part most teams either overcomplicate or treat like admin trivia.
145
00:06:57,680 --> 00:06:58,680
Tags are not decoration.
146
00:06:58,680 --> 00:07:03,000
They are the minimum context your engine needs before it can take action without guessing.
147
00:07:03,000 --> 00:07:04,160
Start with the mandatory set.
148
00:07:04,160 --> 00:07:07,920
You need owner, environment, cost, center, and an expiry date or a TTL model.
149
00:07:07,920 --> 00:07:10,800
You also need clean up action and exception reason.
150
00:07:10,800 --> 00:07:14,800
That list is short on purpose because every one of those values answers a specific deletion
151
00:07:14,800 --> 00:07:15,800
question.
152
00:07:15,800 --> 00:07:19,600
You need to know who owns the resource, what kind of environment it is, and which budget
153
00:07:19,600 --> 00:07:20,600
it belongs to.
154
00:07:20,600 --> 00:07:24,840
You have to know when it should stop existing, what should happen at that point, and if
155
00:07:24,840 --> 00:07:26,800
it must stay, you need to know why.
156
00:07:26,800 --> 00:07:29,320
You can add more, but only add them for a specific reason.
157
00:07:29,320 --> 00:07:32,960
Workload name helps when one team runs several apps and data classification matters if the
158
00:07:32,960 --> 00:07:35,760
engine needs to avoid sensitive workloads.
159
00:07:35,760 --> 00:07:38,040
Criticality helps with rooting and approval logic.
160
00:07:38,040 --> 00:07:41,640
Created data is useful too, but don't build your model around age alone because age is
161
00:07:41,640 --> 00:07:42,720
a weak signal.
162
00:07:42,720 --> 00:07:46,440
An old resource can still be valid, while a brand new one can already be waste.
163
00:07:46,440 --> 00:07:50,000
Age tells you the duration, but it doesn't tell you the intent.
164
00:07:50,000 --> 00:07:52,400
Expiry date tells you the intent, or TTL does.
165
00:07:52,400 --> 00:07:55,960
If your process calculates an expiry from the day of creation, that is the difference
166
00:07:55,960 --> 00:07:58,480
between passive reporting and life cycle control.
167
00:07:58,480 --> 00:08:02,480
The tag doesn't just describe the resource, it declares the resources expected end.
168
00:08:02,480 --> 00:08:05,640
Owner is equally important, and it isn't just for showback.
169
00:08:05,640 --> 00:08:09,480
If the engine wants to notify someone, request approval, or prove that nobody responded
170
00:08:09,480 --> 00:08:13,560
before deletion it needs a real owner path, team names can work if they map cleanly to an
171
00:08:13,560 --> 00:08:18,120
operational queue, but free form names like "the platform guys" do not.
172
00:08:18,120 --> 00:08:22,520
Clean up action is where the automation becomes explicit, delete, notify, quarantine.
173
00:08:22,520 --> 00:08:23,880
Ignore if you really must.
174
00:08:23,880 --> 00:08:26,440
If you have a value you choose, you have to standardize them early.
175
00:08:26,440 --> 00:08:29,760
The same goes for environment values like dev, test, and prod.
176
00:08:29,760 --> 00:08:31,480
Pick the set and hold it.
177
00:08:31,480 --> 00:08:36,640
If one team writes production, another writes prod, and a third writes live, your workflow
178
00:08:36,640 --> 00:08:39,440
turns into text cleanup instead of governance.
179
00:08:39,440 --> 00:08:41,760
Exception reason needs that same discipline.
180
00:08:41,760 --> 00:08:46,040
Use it to protect shared platforms, regulated systems, freeze periods, or short term business
181
00:08:46,040 --> 00:08:47,040
holds.
182
00:08:47,040 --> 00:08:51,280
Don't use it as a lazy escape hatch with values like "temporary" or "do not touch".
183
00:08:51,280 --> 00:08:53,600
If people can write anything, they will.
184
00:08:53,600 --> 00:08:57,400
Once free text enters the system, your automation stops trusting the data.
185
00:08:57,400 --> 00:08:59,240
Inheritance matters here more than perfection.
186
00:08:59,240 --> 00:09:03,360
Apply tags at the resource group where lifecycle context usually starts, and then inherit
187
00:09:03,360 --> 00:09:05,440
them down to child resources with policies.
188
00:09:05,440 --> 00:09:09,440
That gives you broad coverage without turning every deployment into manual tag entry.
189
00:09:09,440 --> 00:09:13,800
For older estates, you can use modified policies with remediation tasks to fill gaps instead
190
00:09:13,800 --> 00:09:15,400
of waiting for a full rebuild.
191
00:09:15,400 --> 00:09:16,960
Then you tighten the screws.
192
00:09:16,960 --> 00:09:19,640
Start with modify because it repairs the environment.
193
00:09:19,640 --> 00:09:23,380
Move to deny only when teams know the rules and the pipeline supports them.
194
00:09:23,380 --> 00:09:27,500
If you deny too early, people will blame governance for their problems, but if you deny after
195
00:09:27,500 --> 00:09:30,740
the model is clear, it just feels like a normal part of the process.
196
00:09:30,740 --> 00:09:34,340
You also need a recurring audit, and resource graph is the right tool for that.
197
00:09:34,340 --> 00:09:35,340
Run it weekly.
198
00:09:35,340 --> 00:09:39,420
Look for missing tags, bad values, expired resources that are still alive, and resources whose
199
00:09:39,420 --> 00:09:42,620
tag pattern no longer matches the resource group that contains them.
200
00:09:42,620 --> 00:09:44,620
If you remember one thing here, remember this.
201
00:09:44,620 --> 00:09:47,980
Deletion only feels dangerous when the context is weak.
202
00:09:47,980 --> 00:09:51,660
Strong tags turn cleanup from a risky guess into a controlled decision.
203
00:09:51,660 --> 00:09:56,480
Once that context is reliable, the workflow can finally do the part people keep postponing.
204
00:09:56,480 --> 00:09:59,620
It can act, building the logic app cleanup flow.
205
00:09:59,620 --> 00:10:03,280
Now the workflow needs a place to live, and for most teams, the best starting point is
206
00:10:03,280 --> 00:10:04,900
logic app's consumption.
207
00:10:04,900 --> 00:10:08,940
It isn't that the standard version is bad, but this engine should stay cheap when nothing
208
00:10:08,940 --> 00:10:09,940
is happening.
209
00:10:09,940 --> 00:10:13,460
Cleanup volume usually changes from week to week, and the consumption model handles that
210
00:10:13,460 --> 00:10:17,220
naturally because there is no fixed monthly floor just for existing.
211
00:10:17,220 --> 00:10:20,460
You pay when the engine runs, so if it barely runs, it barely costs.
212
00:10:20,460 --> 00:10:24,820
That matters for governance automation because the whole point is to remove waste, not to
213
00:10:24,820 --> 00:10:29,060
introduce a new always on platform bill before you've even proven the value, set the trigger
214
00:10:29,060 --> 00:10:30,220
on a schedule.
215
00:10:30,220 --> 00:10:34,500
Of hours usually work best, especially for non-production cleanup, because the workflow
216
00:10:34,500 --> 00:10:37,780
can scan and delete with less risk of hitting active changes.
217
00:10:37,780 --> 00:10:40,900
This still gives teams a predictable window they can plan around.
218
00:10:40,900 --> 00:10:45,060
Scope it from the top where possible, like a management group if your state is mature enough,
219
00:10:45,060 --> 00:10:47,260
or a subscription if you need to start smaller.
220
00:10:47,260 --> 00:10:51,200
The important part is consistency, not being overly ambitious on day one.
221
00:10:51,200 --> 00:10:52,980
The first real action is discovery.
222
00:10:52,980 --> 00:10:58,020
Use Azure resource graph to query for candidates like expired sandboxes, unattached disks, or
223
00:10:58,020 --> 00:10:59,780
resource groups tagged for cleanup.
224
00:10:59,780 --> 00:11:04,300
You want the workflow to build a candidate list from the actual state of the environment,
225
00:11:04,300 --> 00:11:06,660
not from a spreadsheet somebody exported last week.
226
00:11:06,660 --> 00:11:10,380
Once discovery becomes a manual task, the engine is already drifting away from the environment
227
00:11:10,380 --> 00:11:11,780
it claims to govern.
228
00:11:11,780 --> 00:11:13,860
From there, the flow turns into decisions.
229
00:11:13,860 --> 00:11:17,060
Take each candidate and filter it through a small decision path.
230
00:11:17,060 --> 00:11:22,020
At exclude protected workloads based on environment or criticality tags, then validate that the
231
00:11:22,020 --> 00:11:24,340
required tags are present and usable.
232
00:11:24,340 --> 00:11:27,580
After that, inspect for locks and check whether dependencies exist that would break the
233
00:11:27,580 --> 00:11:28,860
deletion order.
234
00:11:28,860 --> 00:11:31,660
Only then should the workflow move to the action branch.
235
00:11:31,660 --> 00:11:33,500
That sequence is where most people cut corners.
236
00:11:33,500 --> 00:11:37,420
They jump from the query straight to the delete action, because the query looked clean, but
237
00:11:37,420 --> 00:11:41,300
a good query only finds candidates and does not prove safety.
238
00:11:41,300 --> 00:11:45,100
The workflow has to do that proof step by step, because each Azure resource behaves a
239
00:11:45,100 --> 00:11:46,260
little differently.
240
00:11:46,260 --> 00:11:49,660
The flow should branch by resource type instead of pretending every deletion works the
241
00:11:49,660 --> 00:11:50,660
same way.
242
00:11:50,660 --> 00:11:52,940
A virtual machine is not an unattached disk.
243
00:11:52,940 --> 00:11:56,940
A network interface is not a stale resource group, and an old app resource may have child
244
00:11:56,940 --> 00:11:59,860
objects or service links that need a different delete path.
245
00:11:59,860 --> 00:12:01,860
Build type specific branches instead.
246
00:12:01,860 --> 00:12:05,340
Keep the shared checks at the top, then split into smaller parts where the delete action
247
00:12:05,340 --> 00:12:08,980
and validation logic fit the actual resource you are dealing with.
248
00:12:08,980 --> 00:12:12,700
For authentication, use managed identity everywhere you can.
249
00:12:12,700 --> 00:12:17,220
That removes stored credentials from the design and avoids old patterns that create extra
250
00:12:17,220 --> 00:12:18,420
security debt.
251
00:12:18,420 --> 00:12:22,120
Give the identity the narrowest permissions the workflow needs at the scopes where it actually
252
00:12:22,120 --> 00:12:23,120
operates.
253
00:12:23,120 --> 00:12:27,020
The engine does not need broad rides across the entire tenant, just to clean up stale dev
254
00:12:27,020 --> 00:12:30,860
assets and every extra permission widens the damage of the workflow or its operators
255
00:12:30,860 --> 00:12:32,180
get misused.
256
00:12:32,180 --> 00:12:34,300
Start with the lowest risk targets first.
257
00:12:34,300 --> 00:12:38,140
Unattached managed disks are a good example, as are expired dev resource groups and temporary
258
00:12:38,140 --> 00:12:40,620
sandbox environments with clear expiry rules.
259
00:12:40,620 --> 00:12:45,460
Those are easier to explain, easier to test, and less likely to create political resistance.
260
00:12:45,460 --> 00:12:49,380
This matters because the first version of the engine is not just a technical rollout, it
261
00:12:49,380 --> 00:12:51,780
is a trust exercise for the whole organization.
262
00:12:51,780 --> 00:12:56,160
For medium risk cases add a pause, send a notification to the owner tag or create an approval
263
00:12:56,160 --> 00:12:57,700
path before deletion.
264
00:12:57,700 --> 00:13:01,260
That gives teams a chance to intervene without turning every cleanup into a service desk
265
00:13:01,260 --> 00:13:02,260
ritual.
266
00:13:02,260 --> 00:13:05,420
You want just enough friction to protect uncertain cases, but not so much friction that
267
00:13:05,420 --> 00:13:07,580
the process becomes another ignored inbox.
268
00:13:07,580 --> 00:13:12,540
Then log everything, ride deletions, skips, approvals and failures into log analytics so you
269
00:13:12,540 --> 00:13:15,220
can prove what the engine checked and why it stopped.
270
00:13:15,220 --> 00:13:19,640
That ordered trail is not just for admin comfort, it is the difference between controlled
271
00:13:19,640 --> 00:13:23,940
automation and a black box that people will shut off the first time something goes wrong.
272
00:13:23,940 --> 00:13:27,360
Add retry logic for transient errors, but be selective.
273
00:13:27,360 --> 00:13:31,220
If Azure returns a temporary failure, go ahead and retry, but if the workflow hits a
274
00:13:31,220 --> 00:13:34,620
lock or a policy conflict you should stop and record it.
275
00:13:34,620 --> 00:13:38,080
Adding the wrong kind of error just wastes runs and hides a design issue under a layer of
276
00:13:38,080 --> 00:13:39,080
noise.
277
00:13:39,080 --> 00:13:42,980
And this is why logic apps fits the job well, this isn't just one delet script on a timer,
278
00:13:42,980 --> 00:13:46,660
it is orchestration across discovery, validation, branching and action.
279
00:13:46,660 --> 00:13:50,820
One workflow many decisions, deletion sounds straight forward until Azure pushes back and
280
00:13:50,820 --> 00:13:53,860
that is exactly where weak designs collapse.
281
00:13:53,860 --> 00:13:56,700
What breaks automated deletion and how to design around it?
282
00:13:56,700 --> 00:14:00,660
The first thing that breaks automated deletion is usually not permissions, it is locks.
283
00:14:00,660 --> 00:14:04,780
A workflow can hold the right role assignments and still fail because Azure resource locks
284
00:14:04,780 --> 00:14:06,740
sit above those expectations.
285
00:14:06,740 --> 00:14:10,940
If a resource carries a cannot delete lock, the delet call stops right there.
286
00:14:10,940 --> 00:14:15,220
If that locked resource sits inside a broader cleanup path, one object can hold up the whole
287
00:14:15,220 --> 00:14:17,860
attempt while the rest of the run waits or gets skipped.
288
00:14:17,860 --> 00:14:20,660
So your engine has to check locks before it tries to be helpful.
289
00:14:20,660 --> 00:14:24,700
That sounds obvious, but lots of cleanup flows only discover locks after the delet call
290
00:14:24,700 --> 00:14:25,900
returns an error.
291
00:14:25,900 --> 00:14:29,940
By then you've already burned a run and created noise in the logs, which teaches teams that
292
00:14:29,940 --> 00:14:31,700
automation is unreliable.
293
00:14:31,700 --> 00:14:35,420
Check first, record the lock, mark the resources protected and then move on.
294
00:14:35,420 --> 00:14:38,180
Dependencies are the next problem and they are less visible.
295
00:14:38,180 --> 00:14:40,980
Azure doesn't just store resources, it stores relationships.
296
00:14:40,980 --> 00:14:44,540
A VM can still point to a disk or a nickly can still sit under a machine that hasn't been
297
00:14:44,540 --> 00:14:45,780
removed yet.
298
00:14:45,780 --> 00:14:49,700
Managed services create child resources you didn't build directly and some resources are
299
00:14:49,700 --> 00:14:54,300
owned by another service through a managed by property, which means deleting the child
300
00:14:54,300 --> 00:14:56,380
object directly may fail.
301
00:14:56,380 --> 00:14:59,900
This is where deletion order matters, you can't treat the estate like a flat list.
302
00:14:59,900 --> 00:15:03,780
And child order has to be part of the design, especially for resource groups that contain
303
00:15:03,780 --> 00:15:05,180
mixed services.
304
00:15:05,180 --> 00:15:07,940
In some cases, the right answer isn't to delete the child at all.
305
00:15:07,940 --> 00:15:11,660
It is to remove the parent service that owns the rest of the stack, then you hit soft
306
00:15:11,660 --> 00:15:13,620
delet and recovery settings.
307
00:15:13,620 --> 00:15:16,420
Some Azure services don't disappear the way people expect.
308
00:15:16,420 --> 00:15:19,940
They move into a recoverable state or keep data retention behavior after the initial
309
00:15:19,940 --> 00:15:21,020
delet action.
310
00:15:21,020 --> 00:15:25,260
If your engine report success too early, the team thinks the cost and exposure are gone
311
00:15:25,260 --> 00:15:27,420
when they may not be fully gone yet.
312
00:15:27,420 --> 00:15:31,180
Find the workflow to distinguish requested deletion from completed deletion and follow
313
00:15:31,180 --> 00:15:32,900
up on the final state where needed.
314
00:15:32,900 --> 00:15:34,860
There is another trap higher in the stack.
315
00:15:34,860 --> 00:15:36,300
Governance can block governance.
316
00:15:36,300 --> 00:15:41,020
If inherited policy uses deny action or other restrictive controls, your cleanup engine
317
00:15:41,020 --> 00:15:44,460
may collide with the very rules your platform team put in place.
318
00:15:44,460 --> 00:15:45,780
That isn't a reason to weaken policy.
319
00:15:45,780 --> 00:15:49,860
It is a reason to map policy interactions before you turn on deletion.
320
00:15:49,860 --> 00:15:53,820
The engine should know which scopes are allowed and which policy paths require exemption
321
00:15:53,820 --> 00:15:55,860
handling instead of brute force retries.
322
00:15:55,860 --> 00:15:58,740
A safer design starts with exclusions, not ambition.
323
00:15:58,740 --> 00:16:03,260
Production, business critical systems and regulated workloads should be excluded first.
324
00:16:03,260 --> 00:16:07,100
Make the default cleanup set narrow enough that you can explain every rule to an owner
325
00:16:07,100 --> 00:16:08,820
in one short conversation.
326
00:16:08,820 --> 00:16:12,580
Broad automation sounds efficient, but broad automation without trust creates pressure to
327
00:16:12,580 --> 00:16:14,980
shut it down the first time someone gets nervous.
328
00:16:14,980 --> 00:16:18,740
And before live deletion run dry, dry run mode is one of the best ways to build confidence
329
00:16:18,740 --> 00:16:22,060
because teams can see exactly what would have been deleted and why.
330
00:16:22,060 --> 00:16:26,740
That exposes weak tags, hidden dependencies and bad assumptions before anything disappears.
331
00:16:26,740 --> 00:16:29,580
It also changes the conversation from fear to evidence.
332
00:16:29,580 --> 00:16:33,180
For uncertain resource classes use quarantine instead of immediate deletion.
333
00:16:33,180 --> 00:16:36,500
Move them into a tighter review state or apply a temporary control path that flags them
334
00:16:36,500 --> 00:16:37,900
for an owner response.
335
00:16:37,900 --> 00:16:41,940
This works well when confidence is moderate but not strong enough for direct removal.
336
00:16:41,940 --> 00:16:45,260
It buys safety without falling back into endless manual review.
337
00:16:45,260 --> 00:16:47,140
Keep exceptions simple too.
338
00:16:47,140 --> 00:16:50,940
If the exception process takes weeks, people will stop using the system properly and start
339
00:16:50,940 --> 00:16:52,340
inventing ways around it.
340
00:16:52,340 --> 00:16:56,460
A short, visible path with clear reasons works better than a heavy approval maze.
341
00:16:56,460 --> 00:17:00,740
On the security side, keep the managed identity narrow and fully auditable, give it only the
342
00:17:00,740 --> 00:17:03,900
rolls and scopes the engine needs and nothing wider.
343
00:17:03,900 --> 00:17:06,740
When deletion fails, don't treat that as random noise.
344
00:17:06,740 --> 00:17:11,540
Fail deletions usually expose something useful like broken ownership, bad architecture or
345
00:17:11,540 --> 00:17:13,140
unmanaged dependencies.
346
00:17:13,140 --> 00:17:18,380
The failed run is telling you where the environment still doesn't understand its own life cycle.
347
00:17:18,380 --> 00:17:22,260
Knowing whether the engine is actually working, once your workflow goes live, the first thing
348
00:17:22,260 --> 00:17:24,780
most teams look for is a savings number.
349
00:17:24,780 --> 00:17:27,620
That number matters, but it is too small on its own.
350
00:17:27,620 --> 00:17:30,980
Reclamed cost only tells you what got cleaned up after the waste already existed.
351
00:17:30,980 --> 00:17:32,900
A mature engine should do more than that.
352
00:17:32,900 --> 00:17:36,340
It should reduce the amount of waste that ever appears in the first place.
353
00:17:36,340 --> 00:17:37,580
That is why you need two views.
354
00:17:37,580 --> 00:17:41,260
The first view is reclaimed cost, which tracks what the engine actually removed from the
355
00:17:41,260 --> 00:17:42,260
bill.
356
00:17:42,260 --> 00:17:46,460
The second view is prevented cost, which you can track through an effective avoidance rate.
357
00:17:46,460 --> 00:17:48,580
The second view asks a much better question.
358
00:17:48,580 --> 00:17:53,060
It asks how much spend never landed because your system enforced discipline before drift turned
359
00:17:53,060 --> 00:17:54,060
into waste.
360
00:17:54,060 --> 00:17:56,700
One measures cleanup, the other measures behavior change.
361
00:17:56,700 --> 00:17:59,940
Then you need to check your tag quality because savings without context will eventually
362
00:17:59,940 --> 00:18:00,940
fool you.
363
00:18:00,940 --> 00:18:03,580
Track the percentage of spend attached to valid tags.
364
00:18:03,580 --> 00:18:08,260
Separately, track the percentage of deletable resources that still have a clear owner path.
365
00:18:08,260 --> 00:18:12,100
If the bill is getting cleaner, but ownership is still vague, you haven't actually fixed
366
00:18:12,100 --> 00:18:13,500
the operating model.
367
00:18:13,500 --> 00:18:15,940
You have only cleaned up a few visible leftovers.
368
00:18:15,940 --> 00:18:18,060
Workflow health belongs on that same dashboard.
369
00:18:18,060 --> 00:18:23,140
You need to look at run success rates, failed runs, and the mean time it takes to fix things.
370
00:18:23,140 --> 00:18:25,580
But pay special attention to skipped resources.
371
00:18:25,580 --> 00:18:27,100
Skips matter more than people think.
372
00:18:27,100 --> 00:18:30,900
They show you where the engine sees risk, where it lacks context, or where it hits a rule
373
00:18:30,900 --> 00:18:32,580
it cannot resolve on its own.
374
00:18:32,580 --> 00:18:34,780
A low-failure count looks good on a slide.
375
00:18:34,780 --> 00:18:38,940
But if your skips keep rising, your estate is just pushing uncertainty back into the process.
376
00:18:38,940 --> 00:18:40,460
Watch your drift over time.
377
00:18:40,460 --> 00:18:43,140
Do not rely on a static monthly snapshot.
378
00:18:43,140 --> 00:18:44,340
Compliance decays quietly.
379
00:18:44,340 --> 00:18:48,420
A single report can look fine while new exceptions and unmanaged deployments build up behind
380
00:18:48,420 --> 00:18:49,420
the scenes.
381
00:18:49,420 --> 00:18:51,540
Week over week patterns tell the real story.
382
00:18:51,540 --> 00:18:54,980
You need to know if unknown resources are shrinking and if expired assets are getting
383
00:18:54,980 --> 00:18:56,940
removed faster than before.
384
00:18:56,940 --> 00:19:01,700
Check if policy gaps are closing, or if teams are finding new ways to land resources outside
385
00:19:01,700 --> 00:19:02,940
the expected path.
386
00:19:02,940 --> 00:19:05,060
Different audiences need different proof.
387
00:19:05,060 --> 00:19:07,500
Executives want fewer billing surprises and cleaner chargebacks.
388
00:19:07,500 --> 00:19:10,580
They want to know if the cloud estate is becoming more predictable.
389
00:19:10,580 --> 00:19:11,580
Engineers want something else.
390
00:19:11,580 --> 00:19:15,340
They want fewer clean-up tickets and less background noise in the subscriptions they work in every
391
00:19:15,340 --> 00:19:16,340
day.
392
00:19:16,340 --> 00:19:20,180
If both groups feel less friction, the engine is doing more than just deleting files.
393
00:19:20,180 --> 00:19:22,140
It is improving how the platform behaves.
394
00:19:22,140 --> 00:19:26,420
You should also compare the cost of your automation against the manual effort you avoided.
395
00:19:26,420 --> 00:19:30,340
Even a lightweight workflow looks smart when you measure the hours it saves.
396
00:19:30,340 --> 00:19:34,260
It removes the need for chasing owners, checking all deployments, and cleaning simple resource
397
00:19:34,260 --> 00:19:35,580
classes by hand.
398
00:19:35,580 --> 00:19:38,740
The question isn't whether automation is free, the question is whether repeating manual
399
00:19:38,740 --> 00:19:40,060
governance is cheaper.
400
00:19:40,060 --> 00:19:41,560
In practice, it rarely is.
401
00:19:41,560 --> 00:19:44,080
And do not treat these metrics as a celebration deck.
402
00:19:44,080 --> 00:19:45,700
Use them to tighten the system.
403
00:19:45,700 --> 00:19:49,400
If one tag value causes repeated skips, you need to fix the taxonomy.
404
00:19:49,400 --> 00:19:53,920
If one resource type fails often, you need to narrow the scope or improve the logic.
405
00:19:53,920 --> 00:19:58,440
If one subscription keeps drifting, that is a management issue, not a workflow issue.
406
00:19:58,440 --> 00:20:02,280
Measurement should feed the next policy adjustment and the next expansion step.
407
00:20:02,280 --> 00:20:04,240
Success is not a pretty savings chart.
408
00:20:04,240 --> 00:20:08,400
Success is a platform where ownership is clear, drift is low, and the organization stops
409
00:20:08,400 --> 00:20:10,760
asking if a resource still belongs there.
410
00:20:10,760 --> 00:20:13,120
The right way to ship this is to start narrow.
411
00:20:13,120 --> 00:20:18,280
Pick one clean up class, first, like expired dev resource groups, or unattached discs.
412
00:20:18,280 --> 00:20:21,520
A small scope teaches you more than a big design review ever will.
413
00:20:21,520 --> 00:20:24,680
Once the tags and the logic prove themselves there, the model becomes much easier to grow
414
00:20:24,680 --> 00:20:26,080
without any guesswork.
415
00:20:26,080 --> 00:20:27,760
Keep that first tag set small.
416
00:20:27,760 --> 00:20:29,520
Backfill with a modify policy.
417
00:20:29,520 --> 00:20:32,960
Block with a deny policy only after the contract is clear to everyone.
418
00:20:32,960 --> 00:20:37,080
Run the workflow in audit mode first, review the skips, and then turn on deletion when the
419
00:20:37,080 --> 00:20:38,240
evidence supports it.
420
00:20:38,240 --> 00:20:42,000
This is the shift, stop treating cloud waste like a reporting issue, start treating it like
421
00:20:42,000 --> 00:20:45,080
a life cycle control issue, if this changed how you think.
422
00:20:45,080 --> 00:20:48,680
Follow me, Mercopeaters on LinkedIn, and if you want more of this, leave a review, it helps
423
00:20:48,680 --> 00:20:50,000
more people find it.
424
00:20:50,000 --> 00:20:52,920
Share this with your team, especially if you are dealing with this right now.

Founder of m365.fm, m365.show and m365con.net
Mirko Peters is a Microsoft 365 expert, content creator, and founder of m365.fm, a platform dedicated to sharing practical insights on modern workplace technologies. His work focuses on Microsoft 365 governance, security, collaboration, and real-world implementation strategies.
Through his podcast and written content, Mirko provides hands-on guidance for IT professionals, architects, and business leaders navigating the complexities of Microsoft 365. He is known for translating complex topics into clear, actionable advice, often highlighting common mistakes and overlooked risks in real-world environments.
With a strong emphasis on community contribution and knowledge sharing, Mirko is actively building a platform that connects experts, shares experiences, and helps organizations get the most out of their Microsoft 365 investments.







