Azure Health Check HTML Report for governance, compute, storage, network, Key Vault, Activity Log, SQL and Azure Policy.
This PowerShell script generates a full HTML-based health report across every Azure subscription available in your current context.
It analyses common governance gaps, security misconfigurations, compute/storage/network risks, Key Vault configuration, upcoming expirations, and more.
- Detects Resource Groups without management locks
- Highlights potential accidental-deletion risks
- Lists all VMs not protected by Azure Backup
- Cross-checks across all Recovery Services Vaults
- VMs with legacy disks (HDD / unmanaged)
- VMs without backup
- VMs with high CPU β flags VMs whose P95 CPU utilisation (hourly average over 7 days) exceeds the threshold (default 80%)
- Unattached disks
- Unattached Public IPs
- Stopped VMs β VMs in OS-stopped state (not deallocated). These still incur compute charges.
- TLS version issues (TLS 1.0 / 1.1)
- Blob public access enabled
- Soft delete status (Blob / File)
- Replication tier (GRS, ZRS, etc.)
- Public network access β Storage Accounts with no network firewall (DefaultAction: Allow)
- Subnets without NSG
- NICs without NSG
- Inbound NSG rules exposing RDP/SSH to the Internet
- Vaults without purge protection
- Secrets, certificates and keys expiring within 90 days
- Checks whether subscription-level Activity Log diagnostics are configured
- Supports any destination: Log Analytics, Storage Account, Event Hub, or Partner
- Inventory of all SQL instances across subscriptions:
- Azure SQL logical servers
- Azure SQL Managed Instances
- SQL Server on Azure VMs (SQL IaaS Agent)
- Inventory of all Policy assignments at subscription scope
- Shows display name, scope, and policy definition ID
- Defender plan coverage per subscription (Standard vs Free)
- Free tier means the workload is not actively monitored by Defender
- Resource groups and VMs with no tags
- Or missing required tags if
-RequiredTagsis specified
- App Services with
PublicNetworkAccessnot explicitly set toDisabled - Storage Accounts with no network firewall (
DefaultAction: Allow) - SQL logical servers with
publicNetworkAccessnot set toDisabled - SQL Managed Instances with
publicDataEndpointEnabledset totrue
- Permanent
OwnerandContributorrole assignments for users and groups (i.e. not service principals or managed identities) - These direct permanent assignments should be replaced with PIM-eligible assignments to enforce just-in-time access
- Note: PIM-eligible (not yet activated) assignments are not returned by the Azure RBAC API and are therefore not listed
The script generates a single HTML dashboard with:
- Summary cards
- Donut chart (risk by category)
- Heat map (subscription vs issue type)
- Top 5 subscriptions by risk
- Per-subscription detailed tables
- Export-to-CSV buttons for each section
Install-Script -Name Invoke-AzHealthCheck -ForceInvoke-AzHealthCheck
Invoke-AzHealthCheck -OpenAfterExport| Parameter | Type | Default | Description |
|---|---|---|---|
-OpenAfterExport |
Switch | $false |
Automatically opens the HTML report after generation |
-CpuHighThresholdPercent |
Int | 80 |
CPU P95 threshold (%) above which a VM is flagged as high-CPU |
-CpuTopNPerSubscription |
Int | 20 |
Maximum number of high-CPU VMs reported per subscription |
-RequiredTags |
String[] | @() |
List of required tag names to check (e.g. 'Environment','Owner'). If empty, reports resources with no tags at all |
C:\TEMP\Health Check script\
Azure-HealthCheck_<TenantId>_MULTI_<timestamp>.html
The script is read-only and does not modify any resources.
| Component | Required Role |
|---|---|
| Resources (VMs, RGs, storage, network, App Services, etc.) | Reader |
| Key Vault expiry metadata | Key Vault Secrets User (or custom: secrets/read, keys/read, certificates/read) |
| Recovery Services Vault (backup items) | Reader (or Backup Reader in restricted tenants) |
| CPU metrics | Monitoring Reader (or Microsoft.Insights/metrics/read) |
| Role assignments (Privileged Identity check) | Reader (includes Microsoft.Authorization/roleAssignments/read) |
- Managed Identity gaps β VMs/App Services still using service principal passwords
- Entra ID guest users β subscriptions with high numbers of guests with elevated roles
- Stopped (deallocated) VMs β off for >30 days, still incurring disk costs
- Undersized/idle VMs β VMs running at <5% avg CPU (complement to the existing high CPU check)
- Old snapshots β disk snapshots older than 90 days
- Diagnostic settings on resources β Key Vaults, Storage Accounts, NSGs missing diagnostics
- Azure Advisor integration β pull high/medium severity recommendations into the report
- Email report β send the HTML report via SendGrid/SMTP after generation
- Dark mode UI for HTML report
- Scheduled run via Azure Automation β runbook wrapper to save reports to Blob Storage on a schedule
- PDF export
- Comparison mode β diff two reports to highlight what's new or fixed since the last run
Pull requests are welcome!
Feel free to submit issues or feature requests using GitHub Issues.
JoΓ£o Paulo Costa
Blog: https://getpractical.co.uk
LinkedIn: https://www.linkedin.com/in/jpsantoscosta
This project is licensed under the MIT License.