Azure Microsoft PowerShell

Azure Health Check – A Free Script to Audit and Visualise Cloud Hygiene

Are you running Azure subscriptions and want a quick, human-friendly overview of your governance, compute, storage, network and Key Vault hygiene?
The Azure Health Check PowerShell script gives you exactly that — scanning multiple subscriptions, flagging weak spots, and producing a clean interactive HTML report (with charts!).

Why this matters

Large and growing Azure estates can easily drift into insecure or unsupported configurations: unprotected VMs, public storage blobs, missing resource locks, orphaned disks, exposed network ports — all of which can lead to security, availability or compliance issues.

Yet manually auditing each subscription is time-consuming. That’s where automation helps. With this script, you get a multi-subscription health summary, scored, visualised and exportable — ideal for periodic reviews, customer readiness checks, or even compliance audits.

What the script does

When you run the script, it performs a comprehensive sweep of your Azure subscriptions (state: Enabled / Warned) and reports the following:

  • ✅ Resource groups without management locks — possible accidental deletion or change risk.
  • ✅ Virtual machines missing Azure Backup protection.
  • ✅ VMs using legacy/unmanaged disks (HDD / VHD) — compute hygiene risk.
  • ✅ Unattached disks and unused public IPs — potential untracked costs or attack surface.
  • ✅ Storage accounts with weak or insecure settings: TLS version < 1.2, public blob access, soft-delete or replication misconfiguration.
  • ✅ Network exposure — subnets/NICs without Network Security Groups, or NSG rules that expose SSH/RDP to the internet.
  • ✅ Key Vault security issues — vaults without purge protection and secrets/keys/certs expiring soon (within 60–90 days).

At the end it generates a self-contained HTML report including:

  • Summary cards (subscriptions, resource groups, VMs, storage)
  • An interactive risk-category donut chart (global view)
  • A heat-map by subscription vs risk category (shows which subscriptions are “hotspots”)
  • A top-5 subscriptions by issue count bar chart and table
  • Detailed per-subscription tables (governance, compute, storage, networking, Key Vault)
  • Export-to-CSV buttons for each table for deeper analysis

✏️ Updated — What the script checks (as of v1.2.0)

This post was originally published in November 2025. The script has expanded significantly since then. Here’s everything that’s been added.


🆕 v1.0.5 — Activity Log, SQL Inventory & Azure Policy

Three new inventory checks were added:

Activity Log diagnostics — checks whether each subscription has Activity Log diagnostic settings configured (to any destination: Log Analytics workspace, Storage Account, Event Hub, or partner solution). Missing Activity Log forwarding means audit trails may not be retained.

SQL Inventory — enumerates all SQL deployments across your subscriptions:

  • Azure SQL logical servers
  • Azure SQL Managed Instances
  • SQL Server on Azure VMs (SQL IaaS Agent)

This is purely an inventory — useful for understanding your SQL surface area and spotting unregistered instances.

Azure Policy — lists all Policy assignments at subscription scope, showing display name, scope, and policy definition ID. Useful for confirming governance baselines are in place.


🆕 v1.0.6 — High-CPU VMs

High-CPU detection — queries Azure Monitor metrics (P95 hourly CPU utilisation over the past 7 days) and flags any VMs exceeding a configurable threshold (default: 80%). This catches chronically over-utilised VMs that may be causing performance issues or are undersized.

You can tune it with parameters:

Invoke-AzHealthCheck -CpuHighThresholdPercent 90 -CpuTopNPerSubscription 10

🆕 v1.1.0 — Defender for Cloud, Stopped VMs & Tagging Gaps

Defender for Cloud coverage — checks whether each Defender plan (VMs, Storage, SQL, App Services, Key Vault, etc.) is on the Standard (paid, actively monitored) tier or Free tier. Free means no active threat detection for that workload.

Stopped VMs (OS-stopped, not deallocated) — VMs that are stopped via the OS but not deallocated from Azure still incur compute charges. This check surfaces those VMs so you can decide whether to deallocate or terminate them.

Resource tagging gaps — reports resource groups and VMs with no tags at all. If you define required tags via the new -RequiredTags parameter, the check flags any resources missing those specific tags:

Invoke-AzHealthCheck -RequiredTags 'Environment','Owner','CostCentre'

🆕 v1.2.0 — Public-Facing Resources & Privileged Identity

Public-facing resources — flags resources with public network access enabled that arguably shouldn’t be:

  • App Services where PublicNetworkAccess is not explicitly set to Disabled
  • Storage Accounts with no network firewall (DefaultAction: Allow)
  • SQL logical servers where publicNetworkAccess is not Disabled
  • SQL Managed Instances with publicDataEndpointEnabled set to true

Each finding includes the resource name, resource group, and subscription — making remediation straightforward.

Privileged Identity — detects permanent Owner and Contributor role assignments for users and groups. These are direct, standing RBAC assignments that should instead be managed via Privileged Identity Management (PIM) to enforce just-in-time access and reduce the standing privilege attack surface.

Note: PIM-eligible assignments (not yet activated) are not returned by the Azure RBAC API, so the check only surfaces permanent direct assignments — which is exactly what you want to catch.

Module Dependencies (Before you run it)

To run the script, you’ll need the following core Azure PowerShell modules installed:

  • Az.Accounts — for authentication and context switching
  • Az.Resources — for resource groups, subscription and lock enumeration
  • Az.Compute — for VM and disk enumeration
  • Az.Network — for public IPs, virtual networks, NICs and NSGs
  • Az.Storage — for storage account configuration and security checks
  • Az.RecoveryServices — for Azure Backup vaults/items
  • Az.KeyVault — for vaults, secrets/keys/certificates

You can install them all at once by running:

Install-Module Az -Scope CurrentUser -Force

Required Access

To run the script successfully, the account must have (at minimum):

👉 Reader role on the subscriptions being scanned
👉 Backup Reader for Azure Backup visibility
👉 Key Vault Reader to list vault settings & key/secret/cert expiry

🔐 Updated permissions requirement

The script remains read-only and requires no write permissions. The only addition since v1.0 is:

New componentRequired role
Role assignments (Privileged Identity check)Reader (includes Microsoft.Authorization/roleAssignments/read)

Everything else continues to work with Reader + Key Vault Secrets User + Monitoring Reader.

Getting Started — Step by Step

Here’s how you use the script:

# 1. Install Az modules (if not already installed)
Install-Module Az -Scope CurrentUser -Force
# 2. Install or update the script
Install-Script -Name Invoke-AzHealthCheck -Force
# 3. Run the script:
Invoke-AzHealthCheck -OpenAfterExport
  • The script will prompt you to log in to Azure (if not already).
  • It will enumerate subscriptions, collect data, compute scores and assemble the HTML report.
  • Once done, it will save the report under C:\TEMP\Health Check script (filename includes tenant ID and timestamp) and — because of -OpenAfterExport — will attempt to open it automatically in your default browser.

You can then:

  • Review the summary cards and charts for a quick high-level overview
  • Drill down per subscription using filters
  • Export any of the detailed tables to CSV (useful for further filtering, reporting or remediation tracking)

When to Run & How to Use

  • Periodic audits — run monthly/ quarterly to catch drift before it becomes a problem
  • Pre-handover reviews — when onboarding/offboarding clients or environments
  • Compliance checkpoints — as a quick “health snapshot” ahead of bigger audits
  • Remediation tracking — export CSVs, track over time, rerun after changes to confirm fix

How it works — At a glance

  1. Authenticate & list all enabled subscriptions
  2. For each subscription: gather resource groups, VMs, disks, storage accounts, public IPs, networking setup, Key Vaults
  3. Analyse data to detect “risks” — e.g. missing backup, legacy disks, insecure storage or open NSG rules
  4. Compute a per-subscription “score” based on configurable weights
  5. Build JSON data for charts (donut, heat map, top-5) + HTML tables
  6. Output a single HTML file with embedded CSS and JS for offline-friendly interactive viewing

Summary

The Azure Health Check script gives you a powerful, automated “bird’s-eye” view of your entire Azure estate — from governance to compute hygiene, storage security, network exposure, and Key Vault safety. With a single run you get a polished, interactive report that’s perfect for stakeholders, audits or cleanup sprints.

If you’re managing multiple subscriptions or want to keep Azure hygiene under control — this is your go-to free health snapshot tool.

Happy auditing — and feel free to fork, adapt or extend!

2 responses to “Azure Health Check – A Free Script to Audit and Visualise Cloud Hygiene”

Leave a Reply to EMERSON SANTOS DA SILVACancel reply

Discover more from Get Practical

Subscribe now to keep reading and get access to the full archive.

Continue reading