Azure Idle Resource Cost Optimizer
On a weekly schedule, the flow uses Azure Resource Manager (with metrics/cost data) to find underused resources — low-CPU VMs, unattached disks, idle public IPs, empty App Service plans — estimates the monthly savings, writes findings to Dataverse, and emails a prioritized rightsizing report to the platform team plus a Teams summary. Surfaces concrete cost-cutting actions.
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 is a weekly Azure cost-optimization sweep built entirely on Azure Resource Manager (ARM). Every Monday at 06:00 UTC it enumerates compute and network resources across the subscription, evaluates each for underuse, estimates the monthly savings of acting, writes every finding to a Dataverse backlog table, and reports a prioritized rightsizing list by email plus a Teams summary.
Why it matters: Cloud waste accumulates quietly. A weekly, quantified list of specific actions turns a vague "reduce spend" goal into a concrete, owner-actionable backlog.
As-built note: your-org has no Azure Resource Manager *connector*, so ARM is called via the built-in HTTP action with ActiveDirectoryOAuth (the FlowLibs ARM pattern — audience = ARM base URL + /). This is the correct connector-first outcome: ARM has no Power Platform connector, so HTTP with AAD OAuth is the sanctioned path. Three underuse categories ship in this build — low-CPU VMs, unattached managed disks, and idle/unassociated public IPs. Empty App Service plans and Azure Advisor enrichment are documented as extensions in the Customization Guide.
Use Case
A platform / FinOps team wants a recurring, evidence-based rightsizing report — *what* is underused, *by how much*, and the *saving* — rather than digging through Cost Management manually. Findings land in Dataverse so they can be triaged, assigned, and tracked as a backlog, and each weekly run is tied together by a correlationId for auditability.
Flow Architecture
Weekly_Monday_0600
Recurrence (Week / Mon 06:00 UTC)Weekly optimization sweep
Init_Correlation_Id
Initialize Variableguid() correlation id stamped on every finding
Init_Arm_Base
Initialize VariableARM base URL from env var
Init_Subscription_Id
Initialize VariableTarget subscription
Init_Low_Cpu_Threshold
Initialize VariableIdle-VM CPU % threshold
Init_Lookback_Days
Initialize VariableMetrics averaging window
Init_Report_Rows
Initialize VariableHTML accumulator for the report table
Init_Finding_Count
Initialize Variable (Integer)Running count of findings
List_VMs
HTTP GET (ARM, AAD OAuth)All VMs in the subscription
List_Disks
HTTP GET (ARM, AAD OAuth)All managed disks
List_Public_IPs
HTTP GET (ARM, AAD OAuth)All public IP addresses
For_Each_VM
Foreach (concurrency 1)Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_ArmBaseUrl | String | https://management.azure.com | ARM base URL (drives the OAuth audience; supports sovereign clouds) |
| flowlibs_AzureSubscriptionId | String | <configure> | Target subscription |
| flowlibs_AzureTenantId | String | <your-tenant-id> | AAD tenant for OAuth |
| flowlibs_AzureClientId | String | <configure> | Service principal client id |
| flowlibs_AzureClientSecret | String | <configure> | Service principal secret (replace with Key Vault reference in prod) |
| flowlibs_LowCpuThreshold | String | 5 | Avg CPU % under which a running VM is flagged idle |
| flowlibs_MetricsLookbackDays | String | 7 | Days of metrics to average for VM CPU |
| flowlibs_FindingsTable | String | flowlibs_costfindings | Dataverse backlog table (entity set name) |
| flowlibs_PlatformEmail | String | platform@contoso.com | Report recipient |
| flowlibs_TeamsGroupId |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| Microsoft Dataverse | shared_commondataserviceforapps | CreateRecord |
| Office 365 Outlook | shared_office365 | SendEmailV2 |
| 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.
- Add App Service plans
- Add a List_App_Service_Plans HTTP GET (Microsoft.Web/serverfarms?api-version=2023-01-01) and a loop flagging plans whose properties.numberOfSites == 0.
- Azure Advisor
- Pull Microsoft.Advisor/recommendations (category Cost) for higher-quality, Microsoft-generated findings and merge them into the report.
- Auto-remediate
- Behind an Approval, delete unattached disks older than N days or deallocate low-CPU VMs.
- Chargeback
- Attribute findings to owning teams via resource tags and route per-team reports.
- Better pricing
- The disk and public-IP savings use simple rate constants ($0.05/GB-mo, $3.65/mo); swap in Retail Prices API calls (as the VM branch already does) for exact figures.
- Production secrets
- Replace flowlibs_AzureClientSecret with an Azure Key Vault reference.
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.01VM average CPU
Extracts the averaged CPU value, defaulting to 100 when no metric data exists.
EXPR.02Idle-VM flag
True when average CPU is below the idle threshold.
EXPR.03VM monthly saving
Hourly retail price times 730 hours for an estimated monthly saving.
EXPR.04Unattached-disk flag
True when a managed disk is unattached.
EXPR.05Idle-public-IP flag
True when a public IP has no IP configuration (unassociated).
EXPR.06OAuth audience
Resolves to https://management.azure.com/.
EXPR.07Metrics timespan
Builds the start/end timespan for the Azure Monitor metrics query.
Customize & download
Generate a ready-to-import copy of this solution with your environment-variable values baked in — available on Base, Pro, or Team.
Upgrade to customize
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.