Skip to content

z-larsen/Azure-FinOps-Multitool

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

190 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AZURE FINOPS MULTITOOL

PowerShell 7.0+ Azure Az Modules License MIT Version 2.20.2

A PowerShell WPF application that scans an Azure tenant and provides a single-pane-of-glass view of costs, tagging health, optimization opportunities, and FinOps maturity — organized around the three FinOps pillars: Understand, Quantify, and Optimize.

A lightweight, read‑only scanner intended for use alongside native Azure Cost Management capabilities and community FinOps tooling. It does not replace Cost Management, FinOps Hubs, or Power BI starter kits. Instead, it helps practitioners quickly identify gaps, validate assumptions, and accelerate conversations during FinOps workshops and scoping engagements.


The Why

Many Azure customers know they have a FinOps problem. They don't know where to start.

The standard path — deploy FinOps Hubs, configure FOCUS exports, build Power BI reports — is powerful, but it assumes time, Power BI expertise, and organizational buy-in that most teams don't have on day one. The result: customers stall before they get their first win.

The Azure FinOps Multitool was built to solve the cold start problem. Run one script, get a complete picture of where your tenant stands: what things cost, what's untagged, what's orphaned, what policies are missing, and what your next three moves should be. No infrastructure to deploy. No dashboards to build. Just answers.

It's designed as the on-ramp and is the tool that surfaces the first wins, and gives customers the foundation they need to grow into the full FinOps Toolkit and Cost Management capabilities Microsoft provides.


What It Does

Area Data Source What You See
Hierarchy Management Groups API Full MG tree with subscriptions, costs inline
Costs Cost Management API (MG scope) Actual month-to-date + forecast per subscription
Cost Trend Cost Management API (6 months) Bar chart showing monthly spend over the last 6 months
Cost Anomalies Cost Trend + per-sub cost data Subscriptions with 25%+ month-over-month cost changes
Resource Costs Cost Management API (per sub) Per-resource spend with type, RG, forecast, % of total — filtered by dynamic spend threshold (0.1% of total)
Contract Billing Accounts API + ARM quotaId EA, MCA, PAYGO, or CSP detection (quotaId fallback)
Tags Azure Resource Graph Every tag name/value in use, untagged resource count
Cost by Tag Cost Management API Spend broken down by CAF allocation tags (CostCenter, BusinessUnit, ApplicationName, etc.) plus auto-backfill of non-priority tags (up to 5 total); auto-fallback to last month
Tag Deploy ARM Tags API (PATCH merge/delete) Inline Add/Remove buttons per tag in the recommendations grid; deploy or remove tags from subscriptions or RGs
AHB Azure Resource Graph Windows VMs, SQL VMs, and SQL DBs missing Hybrid Benefit
Commitments Reservation Summaries + Benefit Utilization API RI and Savings Plan utilization %, underutilized commitments
Orphaned Resources Azure Resource Graph (6 KQL queries) Orphaned disks, unattached IPs/NICs, deallocated VMs, empty ASPs, old snapshots — with per-resource Cost (MTD) and Est. Annual waste
RI / SP Advisor + Reservation Recs API RI and SP recs with Actual (MTD), Forecast, and savings
Advisor Azure Advisor (Cost category) Rightsize, shutdown, delete, modernize recs with cost data
Budget Status Consumption Budgets API Budget vs actual per subscription, % used, risk level; deploy budgets with up to 4 custom thresholds (Actual/Forecasted)
Savings Realized Cost Management (ActualCost + AmortizedCost) Monthly savings from existing RIs, Savings Plans, and AHB
Scorecard All of the above Per-subscription health: cost, tags, optimizations, orphan savings, budget, trend
Tag Recs Cloud Adoption Framework baseline Gap analysis against 7 CAF allocation tags (CostCenter, BusinessUnit, ApplicationName, WorkloadName, OpsTeam, Criticality, DataClassification) with deployment location
Policy Inventory ARM Policy Assignment API + Resource Graph All effective policy and initiative assignments including MG-inherited, with compliance state
Policy Recs CAF-aligned built-in policies & initiatives Missing cost, tagging, security, and monitoring policies with deploy-from-GUI capability
Policy Deploy ARM Policy Assignment API (PUT/DELETE) Inline Deploy/Unassign buttons per policy in the recommendations grid
Policy Remediation Policy Insights API (2021-10-01) Trigger remediation tasks for DeployIfNotExists/Modify policy assignments
Budget Policy ARM Policy Assignment API (PUT) Deploy budget enforcement policies (AuditIfNotExists / DeployIfNotExists) at subscription or MG scope
Billing Billing Accounts/Profiles API Billing accounts, profiles, invoice sections, EA depts
Cost Allocation Cost Management Allocation API Existing cost allocation rules with source/target counts
Idle VMs Azure Monitor Metrics API Running VMs with <5% CPU and minimal network over 14 days — candidates Advisor missed
Storage Tiers Azure Monitor Metrics API Hot-tier storage accounts with low transaction activity — candidates for Cool/Archive
FinOps Guidance All of the above FinOps Maturity Score (0-100) with weighted category breakdown and actionable advice
Resources Static (curated links) Links to FinOps Foundation, Cost Management docs, orphaned resources workbook, toolkit

Prerequisites

  1. Windows with PowerShell 5.1+ (WPF requires Windows)

  2. Az PowerShell modules — install if missing:

    Install-Module Az.Accounts, Az.Resources, Az.ResourceGraph, Az.CostManagement, Az.Advisor, Az.Billing -Scope CurrentUser
  3. Azure RBAC — the signed-in account needs:

    Scanning (read-only):

    Role Scope Why
    Reader Tenant root or MG Read management groups + resources
    Cost Management Reader Tenant root or MG Query cost and forecast data
    Billing Reader Billing account Detect contract type (optional)

    Deploying tags and policies (optional write actions):

    Role Scope Why
    Tag Contributor Subscription or RG Deploy tags via ARM Tags API
    Resource Policy Contributor Subscription or MG Deploy policy assignments (Audit/Deny)
    Owner (or Resource Policy Contributor + User Access Administrator) Subscription or MG Deploy policies with Modify or DeployIfNotExists effects (requires managed identity role assignment)

    If some roles are missing, the tool still works — it just skips the data it can't access and shows warnings. Write permissions are only needed if you click the deploy buttons on the Tags or Policy tabs.

  4. Azure Government — fully supported. Use the Gov Tenant button to authenticate against AzureUSGovernment; use the Commercial Tenant button for standard AzureCloud tenants.


Quick Start

# If downloaded from GitHub, unblock the files first:
Get-ChildItem -Path .\AzureFinOpsMultitool -Recurse | Unblock-File

# Set execution policy if needed (current user only):
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

cd AzureFinOpsMultitool
.\Start-FinOpsMultitool.ps1

Alternative — run with bypass (no policy change required):

powershell -ExecutionPolicy Bypass -File .\Start-FinOpsMultitool.ps1

"Not digitally signed" error? Windows marks downloaded files as blocked. Run Unblock-File on the extracted folder, or use the -ExecutionPolicy Bypass command above, or right-click the .ps1 file → Properties → check Unblock.

  1. The WPF window opens (no authentication yet)
  2. Click Commercial Tenant (or Gov Tenant for Azure Government) — a browser login opens; after sign-in, a tenant picker dialog lists all accessible tenants
  3. Select a tenant and click Select
  4. Click Scan — the tool runs through 23 data-collection stages with a progress bar
  5. When done, browse the tabs:
    • Overview — cost summary cards, savings realized, budget status, subscription cost table (with orphan savings), top resources by spend, subscription scorecard
    • Cost Analysis -- 6-month cost trend bar chart, cost anomaly flags (25%+ MoM change), pick a tag from the dropdown to see spend by tag value
    • Tags -- tag inventory with unique values, coverage %, CAF compliance check, inline Add/Remove buttons per tag to deploy or remove tags directly on subscriptions/RGs
    • Policy -- policy and initiative assignment inventory, compliance %, CAF-recommended policies and initiatives, clickable buttons to deploy policies with desired effect, remediation tasks for DINE/Modify policies
    • Optimization -- commitment utilization (RI/SP %), orphaned/idle resources with cost data and estimated annual waste, idle VM detection (14-day metrics), storage tier advice, AHB gaps, RI recs, SP recs, Advisor recs
    • Billing -- billing accounts, billing profiles (MCA), invoice sections, EA departments, cost allocation rules
    • FinOps Guidance — pillar-by-pillar assessment with selectable/copyable references
    • Resources — curated links to FinOps Framework, Cost Management, Azure Workbooks, orphaned resources workbook, and more

The Commercial Tenant / Gov Tenant buttons show a lock icon: unlocked while choosing, locked once connected.

  1. Click Export Scan Results to save as HTML, CSV, or Power BI template (.pbit)
  2. Click Commercial Tenant or Gov Tenant again any time to switch tenants without restarting

Project Structure

AzureFinOpsMultitool/
├── Start-FinOpsMultitool.ps1              # Entry point — loads modules, launches GUI
├── modules/
│   ├── Initialize-Scanner.ps1           # Auth, tenant picker, environment detection (Commercial/Gov)
│   ├── Get-TenantHierarchy.ps1          # Management group tree
│   ├── Get-ContractInfo.ps1             # Billing account / contract type
│   ├── Get-CostData.ps1                 # Actual + forecast costs (MG scope → per-sub fallback)
│   ├── Get-CostTrend.ps1               # 6-month monthly cost trend data
│   ├── Get-ResourceCosts.ps1            # Per-resource cost breakdown with pagination
│   ├── Get-TagInventory.ps1             # Tag names, values, coverage
│   ├── Get-CostByTag.ps1               # Cost breakdown by tag (MG → per-sub fallback)
│   ├── Deploy-ResourceTag.ps1           # Deploy tags to subscriptions/RGs via ARM API
│   ├── Get-AHBOpportunities.ps1         # Azure Hybrid Benefit gaps
│   ├── Get-CommitmentUtilization.ps1    # RI & Savings Plan utilization data
│   ├── Get-OrphanedResources.ps1        # Orphaned disks, IPs, NICs, VMs, ASPs, snapshots
│   ├── Get-IdleVMs.ps1                  # Idle & underutilized VM detection (14-day metrics)
│   ├── Get-StorageTierAdvice.ps1        # Storage tier optimization (Hot → Cool/Archive)
│   ├── Get-ReservationAdvice.ps1        # RI / SP recs (Resource Graph → REST fallback)
│   ├── Get-OptimizationAdvice.ps1       # Advisor cost optimizations (Resource Graph → REST fallback)
│   ├── Get-BudgetStatus.ps1             # Budget vs actual per subscription
│   ├── Get-SavingsRealized.ps1          # Savings from existing RIs, SPs, and AHB
│   ├── Get-TagRecommendations.ps1       # CAF tag compliance check
│   ├── Get-PolicyInventory.ps1          # Policy assignments + compliance (Resource Graph → per-sub fallback)
│   ├── Get-PolicyRecommendations.ps1    # 15 curated FinOps policies gap analysis
│   ├── Deploy-PolicyAssignment.ps1      # Deploy policy assignments via ARM REST API
│   └── Get-BillingStructure.ps1         # Billing accounts, profiles, invoice sections, cost allocation
├── gui/
│   ├── MainWindow.xaml                  # WPF layout (Azure-themed, virtualized grids, trend chart)
│   ├── app.ico                          # Azure cloud window icon
│   └── skeleton.pbit                    # Power BI template skeleton with pre-built report layout
└── README.md

Each module exports a single function and returns PSCustomObjects. The main script dot-sources all modules and orchestrates the scan via a DispatcherTimer so the UI updates between stages.


How the Scan Works

Stage Module API Used Time
1 Verify tenant context Uses auth from Choose Tenant step <1s
2 Get-TenantHierarchy Get-AzManagementGroup -Expand -Recurse ~3s
3 Get-ContractInfo REST: /providers/Microsoft.Billing/... ~1s
4 Get-CostData REST: Cost Management Query (MG scope) ~5s
5 Get-ResourceCosts REST: Cost Management Query (per sub) ~10s
6 Get-TagInventory Search-AzGraph (cross-subscription) ~3s
7 Get-CostByTag REST: Cost Management Query + tag group ~5s
8 Get-CostTrend REST: Cost Management (Monthly, 6 months) ~3s
9 Get-AHBOpportunities Search-AzGraph (3 queries) ~3s
10 Get-CommitmentUtilization REST: Reservation Summaries + Benefit Util API ~5s
11 Get-OrphanedResources Search-AzGraph (6 KQL queries) ~3s
12 Get-IdleVMs REST: Azure Monitor Metrics (CPU + Network, 14-day) ~5-15s
13 Get-StorageTierAdvice REST: Azure Monitor Metrics (Transactions + Capacity, 30-day) ~5-15s
14 Get-ReservationAdvice Search-AzGraph (advisorresources) + Reservation Recs API ~3s
15 Get-OptimizationAdvice Search-AzGraph (advisorresources) ~3s
16 Get-BudgetStatus REST: Consumption Budgets API (per sub) ~3s
17 Get-SavingsRealized REST: Cost Management (ActualCost + AmortizedCost) + ARG; skipped if no commitments detected in stage 10 ~5s
18 Get-TagRecommendations Local comparison + tag location map <1s
19 Get-PolicyInventory ARM REST API (all effective) + Resource Graph compliance ~3s
20 Get-PolicyRecommendations Local comparison (no API call) <1s
21 Get-BillingStructure REST: Billing Accounts/Profiles/Sections ~3s

Performance Note: The tool is adaptive — it detects tenant size and optimizes accordingly. Cost queries try management-group scope first (one call for all subs). Policy inventory uses Resource Graph (policyresources table) for a single cross-tenant query. Advisor recommendations use advisorresources with automatic per-sub REST fallback. For large tenants (50+ subs) where MG-scope fails, the tool uses sample-first strategies: test 3 subs before iterating 300+, skip forecast queries, and short-circuit when data is absent. Budget queries sample 10 subs first — if no budgets exist, remaining subs are skipped. The UI stays responsive during long iterations via inline status updates. Small tenant (1-10 subs): under 1 minute. Large tenant (300+ subs): 2-5 minutes with MG-scope, 5-10 minutes with per-sub fallback.


Key Design Decisions

Decision Why
MG-scope cost queries with per-sub fallback One call covers all subs; auto-fallback if RBAC blocks MG scope
MonthToDate → TheLastMonth fallback Cost-by-tag auto-retries with last month if current month has no data (early month)
Column-aware API parsing Reads column headers from Cost Management responses instead of hardcoded indices
ARM ResourceId cost lookup Constructs full ARM resource path for cost matching in optimization grids
Lock icon on Choose Tenant Visual feedback — unlocked while picking, locked once connected
Resource Graph for Advisor Single cross-tenant query via advisorresources table; REST fallback if ARG unavailable
Resource Graph for tags + AHB Cross-subscription, fast (KQL), paginated
API pagination (nextLink) Cost Management caps results at ~5000 rows; pagination captures all resources
List<T> instead of array += O(n) vs O(n^2) — critical for tenants with 1000s of resources
DataGrid virtualization WPF only renders visible rows; prevents UI freeze on large datasets
Dynamic resource spend threshold Resource grid includes all resources above 0.1% of total actual spend (min $1); avoids arbitrary caps while filtering noise
DispatcherTimer staged loading UI stays responsive between data-collection stages
Modular .ps1 files Each module testable independently; clean path to C# conversion
CAF tag baseline Comparison against Microsoft's own recommended tags, not arbitrary
Fallback on every module If an API fails (RBAC, throttling), the scan continues gracefully
UTF-8 BOM on all .ps1 files Ensures PS 5.1 reads special characters correctly
100% ASCII XAML All non-ASCII replaced with XML entities to avoid WPF encoding issues
Explicit Azure environment buttons Separate Commercial Tenant / Gov Tenant buttons — no auto-probing of Gov endpoints
Separate tenant / Scan buttons Auth happens once via Commercial Tenant or Gov Tenant; scan is repeatable without re-auth
WPF minimize during browser auth MSAL browser login needs the foreground; scanner minimizes then restores
Tenant picker dialog WPF ListBox shows all accessible tenants; supports 30+ tenants cleanly
LoginExperienceV2 suppressed $env:AZURE_LOGIN_EXPERIENCE_V2=Off prevents Az.Accounts 12+ console subscription picker
Contract type quotaId fallback Infers EA/MCA/PAYGO/Internal from ARM subscription quotaId when Billing API is inaccessible
4-column optimization grids Each recommendation shows Actual (MTD), Forecast, With-X savings, and Annual Savings
Pure WPF bar chart Cost trend drawn with Canvas + Rectangles — no NuGet charting libraries needed
Idle VM detection via Azure Monitor 14-day avg CPU + total network bytes per running VM; idle (<5% CPU, <1MB/day net) and underutilized (<10%) classification
Storage tier advice via Azure Monitor 30-day transaction count + blob capacity per hot-tier storage account; recommend Cool (<1000 tx) or Archive (<100 tx)
Resources tab (static links) Curated FinOps links populated at dashboard build time — no API calls needed; includes orphaned resources workbook
Tag removal retry with backoff 500 errors during tag removal trigger up to 3 retries with 1s/2s exponential backoff
Tag deployment via ARM Tags API PATCH merge to add/update; PATCH delete to remove tags; preserves other existing tags
Tag removal via ARM Tags API Delete operation removes a single tag by name without affecting other tags
Policy deployment via ARM PUT Deploy recommended FinOps policies with user-selected effect (Audit/Deny/etc.)
Policy unassignment via ARM DELETE Remove policy assignments directly from the recommendations grid
Inline action buttons in grids Tag and policy recommendation grids use programmatic TemplateColumns with Add/Remove and Deploy/Unassign buttons per row
Policy remediation via REST Trigger remediation tasks for DeployIfNotExists/Modify assignments via Policy Insights API (2021-10-01)
Budget policy deployment Deploy budget enforcement policies (AuditIfNotExists / DeployIfNotExists) at subscription or MG scope from the Budgets tab
User-defined budget thresholds Budget deploy supports up to 4 threshold entries with Actual/Forecasted type selectors
Dev/Test subscription inclusion Dev/Test subscriptions are no longer skipped during scanning
Tag inventory includes resourcecontainers Resource Graph tag queries union the resourcecontainers table to capture subscription and resource-group-level tags
Orphan savings in scorecard Subscription scorecard and cost table include an Orphan Savings column showing estimated annual waste from orphaned resources
Lazy scope loading for tag deploy Subscription/RG list fetched on first tag deploy click, cached for session
Background runspace for tag deploy Tag deployment runs in a background runspace with 30s timeout; UI stays responsive via DispatcherFrame polling
MG-scope fail-once flag First cost module that gets 401/403 at MG scope sets a shared flag; all subsequent modules skip to per-sub instantly instead of retrying
429 throttle retry Invoke-AzRestMethodWithRetry wraps all REST calls with automatic retry on HTTP 429, exponential backoff, and DispatcherFrame UI-responsive wait
Resource Graph safe wrapper Search-AzGraphSafe runs all Resource Graph calls in background runspaces with 60s timeout, 429 retry, and JSON round-trip to preserve nested properties
Tag compliance location column Tag recommendations grid shows where each present tag is deployed (Subscription / Resource Group)
MG-inherited policy discovery ARM REST API GET policyAssignments returns all effective policies including those inherited from management groups and tenant root
Billing structure discovery Queries billing accounts, profiles, invoice sections, EA departments, and cost allocation rules
Commitment utilization tracking Queries Reservation Summaries + Benefit Utilization APIs to show RI/SP usage %
Orphaned resource detection 6 Resource Graph KQL queries find waste: orphaned disks, unattached IPs/NICs, deallocated VMs, empty ASPs, old snapshots
Budget vs actual monitoring Per-subscription budget query with risk levels: Over Budget, At Risk, Watch, On Track
Savings realized calculation Compares ActualCost vs AmortizedCost by charge type to quantify RI/SP/AHB savings
Orphaned resource cost enrichment Each orphan shows Cost (MTD) and Est. Annual waste from the shared resource cost map; summary totals estimated waste across all costed resources
Shared resource cost map Build-ResourceCostMap builds a single ARM-path-keyed lookup shared by Optimization and Orphan sections — avoids duplicate work
CAF-aligned policy recommendations Policy recs expanded to include Azure Security Benchmark v3, Secure Transfer, Diagnostic Settings, and Allowed Locations; distinguishes Policy vs Initiative assignments
Non-priority tag backfill Cost-by-tag queries the priority list first, then backfills discovered tags up to 5 total (skipping system prefixes like hidden-, aks-managed-)
CAF allocation tag alignment Tag recommendations, cost-by-tag, and maturity scoring all use the same 7 CAF tags: CostCenter, BusinessUnit, ApplicationName, WorkloadName, OpsTeam, Criticality, DataClassification
Weighted tag scoring Allocation score uses per-tag weights: CostCenter and BusinessUnit = 3 pts each, ApplicationName = 2 pts, remaining 4 tags = 1 pt each (12 pts total from tags out of 20)
Commitment-aware savings skip Stage 15 (SavingsRealized) checks commitment data from stage 10; if no RIs or Savings Plans exist, all Cost Management savings queries are skipped (saves 2-120 API calls)
Cost anomaly flagging Per-subscription MoM delta computation; flags 25%+ changes for investigation
Subscription scorecard Composite per-sub view combining cost, tags, optimizations, orphans, budget, trend
Adaptive large-tenant scanning Sample-first, cross-tag short-circuit, budget sampling, forecast skip for 50+ subs
Resource Graph for policy inventory policyresources table replaces per-sub REST; MG-scope compliance in 1 call

Customization

  • Add a tag to recommendations: Edit Get-TagRecommendations.ps1$recommendedTags array (update Get-CostByTag.ps1 $targetTags and the Allocation scoring in Start-FinOpsMultitool.ps1 to match)
  • Change theme colors: Edit gui/MainWindow.xamlWindow.Resources brushes
  • Add a new data module: Create modules/Get-YourData.ps1, dot-source in Start-FinOpsMultitool.ps1, add a scan stage

Roadmap

The current tool covers FinOps discovery and remediation — the first two capabilities in a larger vision.

The longer-term direction is an agentic FinOps layer: a set of autonomous agents that don't just surface findings but act on them continuously. Discovery, anomaly detection, remediation, optimization recommendations, and reporting — orchestrated as a team rather than a one-time scan.

The Azure FinOps Multitool is the foundation that makes that possible: a proven, field-tested data layer with direct write-back to Azure. The first step toward agents has already shipped — an MCP server exposes the scan modules as tools an AI agent can call — and a headless Azure Function runs the same scan unattended. Full multi-agent orchestration comes next.

Near-term

  • Custom tag deployment — Deploy any user-defined tag from the Tags tab
  • Scheduled/headless scan mode — runs unattended as an Azure Function companion (AzureFinOpsFunction) on a timer or HTTP trigger, sharing the same scan modules as the GUI
  • Email report delivery — the headless Function emails the scan report on a daily schedule
  • PDF export with charts

Longer-term

  • C# / WPF conversion (full async, MVVM architecture)
  • [~] Agentic orchestration layer (anomaly agent, optimization agent, reporting agent) — first step shipped: an MCP server exposes the scan modules as tools so an AI agent can query cost, governance, and optimization data on demand; full multi-agent orchestration still to come
  • Power BI integration — auto-generates a .pbit template with 4-page dashboard (Cost Overview, Subscriptions, Optimization, Governance) styled after the FinOps toolkit reports

Completed

  • Firewalled-storage export creationNew-CostExport now attaches a system-assigned managed identity + location to the export so Cost Management can grant it Storage Blob Data Contributor and deliver to storage accounts behind a firewall (matching the Step 2 help text, which previously over-promised). It also registers the Microsoft.CostManagementExports resource provider on the storage account's subscription before creating the export (the portal does this automatically; an API caller must do it explicitly), resolves the storage region when the caller doesn't supply it, and returns clearer messaging about firewall/roleAssignments/write requirements and realistic data-landing time (a few hours, not minutes)
  • RI/SP recommendation de-duplication — Azure Advisor frequently emits several identical recommendation records that differ only by recommendation GUID (overlapping generation cycles), which made a single buy appear 3–6 times in the Reserved Instance grid and inflated the estimated-savings total. Get-ReservationAdvice now captures the displaySKU, region, and displayQty extended properties and collapses records on the meaningful tuple (subscription + resource type + term + SKU + region + qty + savings), keeping one row per distinct recommendation with a DuplicateCount. The RI and SP grids now surface SKU, Region, and Qty columns so each row is self-explanatory
  • 6-month trend multi-month read — the trend now re-reads each export with a 6-month lookback, gathering the newest run folder per billing month instead of reusing the single current-month dataset the cost/resource/tag tabs consume. Each month lives in its own YYYYMMDD-YYYYMMDD folder and is re-emitted daily, so the trend now renders every available month (e.g. Mar–Jun) rather than one. Live-query mode (and the headless Function, which already queries Cost Management for the monthly grain) were unaffected
  • Export reader month-selection fix — the FinOps Hub / Cost Management export reader now selects the run folder whose date-range covers the current billing month instead of the one with the newest blob timestamp. Hubs re-emit the prior (closed) month daily, so picking "newest LastModified" could read last month's full-month total as if it were month-to-date (and then 10× it in the forecast). Selection is now driven by the YYYYMMDD-YYYYMMDD date-range in the blob path, tie-broken by newest run
  • MACC consumption accuracy fix — consumed/remaining now derived from the Consumption Lots API the same way as the Cost Management data factory sample (consumed = originalAmountclosedBalance); the Lots API never returned a usedAmount, so the prior calculation always reported 0 consumed / full remaining
  • Budget vs. actual comparison per subscription — Budget Status module with risk levels
  • Cost trend chart (last 6 months) — WPF Canvas bar chart with per-subscription filter
  • Anomaly detection (spike alerts) — 25%+ MoM cost change flagging per subscription
  • Azure Policy compliance overlay — Policy tab with inventory, compliance %, CAF policy and initiative recs, deploy from GUI
  • Orphaned resource cost data — Per-resource Cost (MTD) and Est. Annual waste columns with total waste summary
  • CAF policy alignment — Policy recommendations expanded to CAF-aligned policies and initiatives (Security Benchmark v3, Secure Transfer, Diagnostic Settings, Allowed Locations)
  • Non-priority tag backfill — Cost-by-tag auto-discovers additional tags beyond the priority list (up to 5 total)
  • CAF allocation tag alignment — Tag list, cost-by-tag, and scoring all aligned to 7 CAF allocation tags with weighted maturity scoring
  • Commitment-aware savings skip — SavingsRealized skips Cost Management queries when no RIs/SPs exist (stage 10 data reuse)
  • Separate Commercial / Gov tenant buttons — Explicit environment selection; Gov cloud is opt-in, no longer auto-probed
  • User-defined budget thresholds — Deploy budgets with up to 4 custom thresholds (Actual/Forecasted type per threshold)
  • Budget policy deployment — Deploy budget enforcement policies (AuditIfNotExists / DeployIfNotExists) from the Budgets tab
  • Policy remediation tasks — Trigger remediation for DeployIfNotExists/Modify policy assignments from the Policy tab
  • Orphan savings in scorecard — Subscription scorecard and cost table show estimated annual waste from orphaned resources
  • Tag inventory includes subscription/RG-level tags — Resource Graph queries union resourcecontainers table
  • Dev/Test subscription inclusion — Dev/Test subs are no longer excluded from scans
  • Inline tag management — Add/Remove buttons directly in the tag recommendations grid
  • Inline policy management — Deploy/Unassign buttons directly in the policy recommendations grid
  • Idle VM detection — 14-day Azure Monitor metrics flag running VMs with <5% CPU and minimal network
  • Storage tier optimization — Hot-tier storage accounts flagged for Cool/Archive migration
  • Resources tab — Curated links to FinOps Framework, Azure Workbooks, orphaned resources workbook
  • Tag Inventory Remove button — Delete any tag directly from the Tag Inventory grid
  • Session action log in HTML report — Exported reports include tags deployed/removed and policies assigned/unassigned during the session

FinOps Maturity Score

The Guidance tab calculates a 0-100 maturity score based on the FinOps Foundation Maturity Model and Microsoft Cloud Adoption Framework. The score is broken into five categories:

Visibility -- 25 pts

Points Criteria
0-10 Tag coverage (% of resources tagged, scaled)
5 Cost data retrieved from Cost Management API
5 6-month cost trend data available
5 Resource-level cost breakdown available

Allocation -- 20 pts

Uses per-tag weights so the tags that matter most for chargeback/showback carry more points:

Points Criteria
3 CostCenter tag present
3 BusinessUnit tag present
2 ApplicationName tag present
1 WorkloadName tag present
1 OpsTeam tag present
1 Criticality tag present
1 DataClassification tag present
4 Cost-by-tag data returns results
4 Azure Cost Allocation Rules configured

Tag variations are recognized (e.g., cost-center, cc, bu, dept, application).

Budgeting -- 15 pts

Points Criteria
5 At least one budget exists
0-5 Budget coverage across subscriptions (% scaled)
5 No subscriptions over budget (3 if some at-risk but none over)

Optimization -- 20 pts

Points Criteria
5 RI/SP utilization >= 80% (3 if >= 60%, 2 if no commitments)
5 Savings realized from existing commitments
0-5 Low Advisor recommendation count (5 if zero, 3 if <= 3, 1 if <= 10)
0-5 Low orphaned resource count (5 if zero, 3 if <= 3, 1 if <= 10)

Governance -- 20 pts

Points Criteria
5 Has Azure Policy assignments
0-5 FinOps-recommended policies assigned (% scaled)
5 Policy compliance >= 80% (3 if >= 50%)
5 Management group hierarchy exists (2 if flat subs only)

Grade Scale

Score Grade
85-100 Excellent
70-84 Good
50-69 Developing
30-49 Foundational
0-29 Getting Started

Author

Zac Larsen — Personal project (not an official Microsoft product)


Support & Responsible Use

This tool queries only public Azure APIs (Cost Management, Resource Graph, Advisor, Billing) against your own Azure subscriptions. It reads subscription metadata (such as subscription IDs/names, regions, budgets, and usage) and writes results locally (console output and HTML/CSV exports); it does not transmit this data off your machine except as required to call Azure APIs.

  • Issues & PRs: Welcome! Please do not include subscription IDs, tenant IDs, internal URLs, or any confidential information.
  • Azure support: For Azure platform issues or outages, contact Azure Support — not this repository.
  • Exported files: Review HTML/CSV exports before sharing externally — they may contain subscription IDs, region information, budgets, and usage details for your environment.

This project may access or process Azure Cost Management, Policy, Resource Graph, or Subscription metadata through Azure APIs.

Execution of this tool may initiate:

  • Resource discovery
  • Policy evaluation
  • Cost data queries
  • Tagging analysis
  • Configuration inspection

Ensure that least‑privilege access is used when running this utility.


References


OSS Project Disclaimer

This repository contains sample tooling developed by a Microsoft employee and is provided for informational and educational purposes only.

This is not an official Microsoft product, service, or supported offering.

This project is provided "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO:

  • Production readiness
  • Security hardening
  • Tenant compatibility
  • Governance alignment
  • Cost optimization outcome guarantees
  • Policy compliance assurance

Microsoft does not provide support for this project under any Microsoft support agreement, Premier/Unified Support plan, or Azure support contract.

No Microsoft service level agreements (SLAs), warranties, or product commitments apply to this repository or any derivative use of its contents.

Execution of this tool within an Azure tenant may result in configuration, cost visibility, tagging analysis, governance evaluation, or policy‑related outcomes depending on permissions granted.

Users are solely responsible for validating all scripts and automation prior to execution in production environments.

About

Interactive WPF-based PowerShell tool that scans an Azure tenant for cost optimization, orphaned resources, idle VMs, tag hygiene, commitment utilization, and policy compliance — with Excel, CSV, JSON, and Power BI exports

Resources

License

Stars

3 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors