Azure Orphaned Resource Cleanup with Approval
On a schedule, the flow finds orphaned Azure resources via Azure Resource Manager - unattached disks, unused NICs and public IPs - compiles a cleanup proposal, routes it through a Power Automate approval, and on approval (with a safety toggle) deletes the confirmed items and logs the action. Reclaims cost and reduces clutter safely.
Provided as-is, without warranty of any kind. Review and test each pattern in a non-production environment before deploying it to live automations. See our Terms.
Overview
This flow safely reclaims Azure cost and reduces estate clutter using the Azure Resource Manager connector. On a weekly schedule it discovers clearly-orphaned resources - unattached managed disks, network interfaces with no VM, and public IPs with no association - compiles an itemized cleanup proposal, routes it through a Power Automate approval, and (only when an explicit auto-delete safety toggle is enabled) deletes the approved items via ARM. Every run posts a summary to Microsoft Teams.
Why it matters: orphaned resources cost money and clutter the estate, but unattended bulk deletion is risky. An approval-gated proposal - plus a dry-run-by-default safety toggle and a protected-tag exclusion - delivers the savings without the danger of deleting something still needed.
Ships Off (Stopped).
Use Case
A platform / cloud-operations team wants regular, human-approved cleanup of clearly-orphaned Azure resources rather than manual hunting or risky unattended deletion. The flow runs weekly, proposes only safe candidates (orphan status confirmed via a per-resource ARM read, protected tags excluded, disks aged past a threshold), and requires a person to approve before anything is removed.
Flow Architecture
Weekly Sunday 03:00 Recurrence
RecurrenceRuns weekly on Sunday at 03:00 Eastern.
Initialize Config & Accumulators
Initialize variableMints a correlation id; binds subscription, approver, auto-delete toggle, Compute/Network api-versions, orphan age, protected tag, Teams ids; seeds the orphans array, proposal HTML/text, and orphan/deleted counters.
Discover Orphans (3 passes)
ARM Resources_List + per-resource GetByIdFor disks, NICs, and public IPs: lists candidates, reads each via GetById, excludes protected-tagged ones, and applies the orphan test (disk Unattached + aged; NIC no VM; public IP no ipConfiguration), appending confirmed orphans to the proposal.
Decision & Approval
Condition + Approvals StartAndWaitForAnApprovalIf any orphans found, composes the proposal and routes a Basic approval to the approver.
Delete (approved + toggle)
ARM Resources_DeleteByIdOn approval, for each orphan, deletes it only when the auto-delete toggle is true (dry-run otherwise) and tallies deletions.
Notify Outcome
Teams - PostMessageToConversationPosts approved/rejected/all-clear summaries with the correlation id.
Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_AzureSubscriptionId | String | <your-subscription-id> | Subscription scanned for orphans. |
| flowlibs_CleanupApproverEmail | String | approver@yourcompany.com | Approver for the cleanup proposal. |
| flowlibs_OrphanCleanupAutoDelete | String | false | Dry-run safety toggle; true enables real deletion after approval. |
| flowlibs_ComputeApiVersion | String | 2023-04-02 | ARM API version for Microsoft.Compute (disks). |
| flowlibs_NetworkApiVersion | String | 2023-09-01 | ARM API version for Microsoft.Network (NICs, IPs). |
| flowlibs_OrphanAgeDays | String | 30 | Min age (days) before a disk is eligible. |
| flowlibs_ProtectedTag | String | do-not-delete | Tag key that hard-excludes a resource when its value is true. |
| flowlibs_TeamsGroupId | String | <your-team-id> | Teams team (group) id for the summary. |
| flowlibs_TeamsChannelId | String | <your-channel-id> | Teams channel id for the summary. |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| Azure Resource Manager | shared_arm | Resources_List Resources_GetById Resources_DeleteById |
| Approvals | shared_approvals | StartAndWaitForAnApproval |
| Microsoft Teams | shared_teams | PostMessageToConversation |
Note — All connections are referenced as solution connection references; the flow is portable between environments as long as a connection is mapped at import time.
Customization Guide
Almost every realistic variant of this flow can be implemented by changing environment variable values. A few cases require small edits inside the flow definition — those are called out explicitly below.
- Enable real deletion
- Set flowlibs_OrphanCleanupAutoDelete to true; until then the flow proposes and reports but never deletes, even after approval.
- Add resource types
- Clone a discovery pass and change the resourceType filter and orphan test (e.g. snapshots, empty resource groups). Keep loops sequential.
- Tune eligibility
- Adjust flowlibs_OrphanAgeDays; change the protected tag key via flowlibs_ProtectedTag.
- Soft-delete first
- Instead of delete, move items to a quarantine resource group (snapshot disks before removal) for an extra safety net.
- Owner notice
- Read an owner tag and notify the owning team before proposing deletion.
Key Expressions
The flow is intentionally light on Power Fx / WDL gymnastics — the heaviest expressions are the branch-name concatenation and the approval outcome check. They are listed below in the order they appear in the flow.
EXPR.01Disk orphaned (unattached + aged)
Unattached disk older than the age threshold.
EXPR.02NIC orphaned
Network interface with no VM.
EXPR.03Protected-tag exclusion
Excludes do-not-delete resources.
EXPR.04Approval outcome
Gate before any deletion.
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.