Content
# Azure Subscription Snapshot
> Deterministic, exhaustive snapshot of an Azure subscription — JSON, Mermaid
> diagrams, HTML report, and a Copilot/MCP-ready knowledge base.
[](https://github.com/jmfloreszazo/azure-subscription-snapshot/actions/workflows/ci.yml)
[](https://learn.microsoft.com/powershell/scripting/install/installing-powershell)
[](https://learn.microsoft.com/cli/azure/install-azure-cli)
[](LICENSE)
[](CONTRIBUTING.md)
Built for the *"I just inherited an Azure subscription, tell me everything"*
moment: resources, configuration, RBAC, identities, policies, locks,
deployments, networking, diagnostics, per-service deep dives. Output is
**deterministic** (sorted-key JSON, alphabetical iteration) so two snapshots of
an unchanged subscription produce **identical files** — drop them in git and
diff over time.
## Table of contents
- [Azure Subscription Snapshot](#azure-subscription-snapshot)
- [Table of contents](#table-of-contents)
- [What you get](#what-you-get)
- [Why another inventory tool?](#why-another-inventory-tool)
- [Requirements](#requirements)
- [Quickstart](#quickstart)
- [Common parameters](#common-parameters)
- [Try it on a representative demo workload](#try-it-on-a-representative-demo-workload)
- [Output layout](#output-layout)
- [Determinism](#determinism)
- [Use it from Copilot Chat (Azure MCP Server)](#use-it-from-copilot-chat-azure-mcp-server)
- [Specialized chat modes \& prompts](#specialized-chat-modes--prompts)
- [Drift detection](#drift-detection)
- [Security \& privacy](#security--privacy)
- [Limitations](#limitations)
- [Troubleshooting](#troubleshooting)
- [FAQ](#faq)
- [Project layout](#project-layout)
- [Contributing](#contributing)
- [Roadmap](#roadmap)
- [License](#license)
## What you get
After a single run you have:
- A **full JSON snapshot** under [`out/`](#output-layout) — inventory,
per-resource detail, RBAC by principal, network topology, policies, locks,
diagnostics, ARM exports, last 90 days of activity.
- A **relationship graph** (`out/10-graph/`) with stable
`nodes.json` / `edges.json` for blast-radius / orphan analysis.
- **Mermaid diagrams** (`out/11-diagrams/`) for architecture, network,
identity and resource types — render them in any Markdown viewer.
- A **self-contained HTML report** (`out/12-report/report.html`) with
embedded diagrams and tables — no external assets.
- A **Copilot/MCP knowledge base**: pre-wired Azure MCP server, four
specialized chat modes, and ready-made prompts so any LLM-powered IDE
(VS Code, Cursor, Claude Desktop, Continue.dev) can answer questions
grounded in the dump with citations.
- A **drift differ** that compares two snapshots and risk-tags every change.
## Why another inventory tool?
Azure already has excellent inventory, governance, compliance, query and IaC
export tools. **Azure Subscription Snapshot** is intentionally narrower: it creates a
deterministic, git-friendly snapshot that is easy for humans and AI agents to
review, diff and cite.
| Need | Azure Subscription Snapshot | [ARI][ari] | [AzGovViz][azgov] | [Steampipe][steampipe] | [azqr][azqr] | [CloudQuery][cloudquery] | [aztfexport][aztfexport] |
| --- | :--: | :--: | :--: | :--: | :--: | :--: | :--: |
| Full subscription inventory | ✅ | ✅ | ✅ | ✅ (queries) | partial | ✅ (to DB) | partial |
| **Deterministic** sorted-key JSON for git diffs | ✅ | ❌ | ❌ | n/a | ❌ | n/a | ❌ |
| Relationship graph (`nodes.json`/`edges.json`) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Mermaid diagrams (architecture, network, RBAC) | ✅ | draw.io | ❌ | ❌ | ❌ | ❌ | ❌ |
| Self-contained HTML report | ✅ | Excel | ✅ | ❌ | Excel | ❌ | ❌ |
| **Copilot Chat / MCP integration** | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Specialized agent chat modes | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Drift differ between snapshots | ✅ | ❌ | partial | query-it-yourself | ❌ | query-it-yourself | Terraform plan |
| Per-service deep dives (AKS/KV/SQL/ACA…) | ✅ | partial | partial | ✅ | ❌ | ✅ | partial |
| ARM export per RG | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| **Bicep reconstruction from the dump** | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Terraform export | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
| Single-file dependency-light entrypoint | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
[ari]: https://github.com/microsoft/ARI
[azgov]: https://github.com/JulianHayward/AzGovViz
[steampipe]: https://github.com/turbot/steampipe-plugin-azure
[azqr]: https://github.com/Azure/azure-quick-review
[cloudquery]: https://github.com/cloudquery/cloudquery
[aztfexport]: https://github.com/Azure/aztfexport
## Requirements
- [PowerShell 7+](https://learn.microsoft.com/powershell/scripting/install/installing-powershell) (`pwsh`)
- [Azure CLI 2.60+](https://learn.microsoft.com/cli/azure/install-azure-cli) (`az`)
- The `resource-graph` extension (auto-installed on first run).
- Subscription-level **`Reader`** role (the dump is read-only).
- For complete RBAC visibility: `Microsoft.Authorization/*/read`.
- Optional: [Bicep CLI](https://learn.microsoft.com/azure/azure-resource-manager/bicep/install)
if you intend to run the demo or use the `reconstruct-iac` prompt locally.
## Quickstart
```pwsh
# 1. Sign in
az login
az account set --subscription "<sub-id-or-name>"
# 2. Dump the whole subscription with diagrams + HTML report
./Invoke-AzureSnapshot.ps1 -OutputDir .\out -GenerateReport
# 3. Or scope it to a single resource group
./Invoke-AzureSnapshot.ps1 -ResourceGroup rg-prod -OutputDir .\out -GenerateReport
# 4. Include app settings & connection strings (controlled environments only)
./Invoke-AzureSnapshot.ps1 -OutputDir .\out -IncludeSensitive
```
Open `out/12-report/report.html` when it finishes.
### Common parameters
| Parameter | Default | Description |
| ------------------- | ---------------- | ------------------------------------------------------------ |
| `-OutputDir` | `.\out` | Folder where the snapshot is written. |
| `-ResourceGroup` | *(all)* | Limit the dump to one resource group. |
| `-GenerateReport` | *off* | Build `out/12-report/report.html` after the JSON layer. |
| `-IncludeSensitive` | *off* | Capture app settings, connection strings, function keys. |
| `-MaxParallel` | `4` | Concurrent `az` calls. Increase for large subscriptions. |
Run `./Invoke-AzureSnapshot.ps1 -?` for the full surface.
## Try it on a representative demo workload
The [`demo/`](demo/) folder ships a Bicep-based, multi-service deployment
(VNet + private endpoints, App Service, SQL serverless, Container Apps, ACR,
Key Vault, Storage, Service Bus, Log Analytics, App Insights, RG lock, policy
assignment) so you can see every diagram light up.
```pwsh
$me = az ad signed-in-user show --query id -o tsv
$upn = az ad signed-in-user show --query userPrincipalName -o tsv
./demo/Deploy-Demo.ps1 -SqlAdminObjectId $me -SqlAdminLogin $upn
./Invoke-AzureSnapshot.ps1 -ResourceGroup rg-azure-snapshot-demo -OutputDir .\out -GenerateReport
./demo/Remove-Demo.ps1 -Force # tear down (removes lock, deletes RG, purges KV)
```
See [`demo/README.md`](demo/README.md) for cost estimates and parameter details.
## Output layout
```text
out/
├─ 00-context/ # account, tenant, providers, tool versions
├─ 01-subscription/ # subscription-level RBAC, policies, locks, budgets
├─ 02-resource-groups/
├─ 03-inventory/ # resources.json (full Resource Graph) + type-summary
├─ 04-resources/ # per-resource detail, diagnostics, RBAC
├─ 05-services/ # AKS, KV, Storage, Web, SQL, Cosmos, APIM, ACA, SB, EH…
├─ 06-network/ # topology, peerings, NSG, route tables, private endpoints
├─ 07-identity/ # managed identities, role assignments by principal
├─ 08-activity-log/ # last 90 days
├─ 09-deployments/ # ARM/Bicep export per RG + deployment history
├─ 10-graph/ # relationship graph (nodes.json, edges.json)
├─ 11-diagrams/ # Mermaid: architecture, network, identity, types
├─ 12-report/ # report.html (self-contained)
├─ _manifest.json # generation metadata
├─ _errors.log # non-fatal failures (insufficient RBAC, throttling…)
└─ _run.log # every az invocation
```
JSON Schemas for the most-consumed files live in
[`schemas/`](schemas/) — point any LLM/validator at them before reasoning
over the dump.
## Determinism
- JSON serialized with **sorted keys** (`ConvertTo-DeterministicJson`).
- Stable iteration order (alphabetical by id).
- Fixed retry backoff (no jitter).
- Timestamps confined to `_manifest.json` and logs.
Two dumps of an unchanged subscription produce **identical files** (modulo
timestamps), so you can `git diff` to track drift.
## Use it from Copilot Chat (Azure MCP Server)
[`.vscode/mcp.json`](.vscode/mcp.json) registers the official
[`@azure/mcp`](https://github.com/Azure/azure-mcp) server. Combined with
[`.github/copilot-instructions.md`](.github/copilot-instructions.md) and the
files in [`prompts/`](prompts/), Copilot will:
- Read facts from `out/` first (the source of truth).
- Use the Azure MCP server to verify or extend when data is stale.
- Cite which file (or MCP tool) it relied on.
Try prompts like:
- *"Which resources expose a public IP and what NSGs protect them?"*
- *"Who has Owner on the Key Vault?"*
- *"Render the dependency graph for the App Service."*
- *"What changed in the last 90 days?"*
## Specialized chat modes & prompts
This is what makes Azure Subscription Snapshot more than a dumper. The repo ships with
ready-made Copilot **chat modes** and **prompts** so any LLM-powered IDE can
work the dump without prompt engineering on your side.
| Chat mode (`.github/chatmodes/`) | When to pick it |
| -------------------------------- | -------------------------------------------------------------- |
| `inheritance-auditor` | You inherited a subscription and need a tour. |
| `security-reviewer` | Prioritized security findings with citations. |
| `cost-hunter` | Find waste; never deploys. |
| `drift-detective` | Diff two dumps, classify changes by risk. |
| Prompt (`prompts/`) | What it does |
| --- | --- |
| `azure-snapshot-analyze` | Generic Q&A grounded in `out/`. |
| `find-orphans` | Inventory ⨉ edges ⨉ activity-log to detect abandoned resources. |
| `blast-radius` | Impact graph for a single resource. |
| `reconstruct-iac` | Starter **Bicep** from `out/09-deployments/`. |
See [`AGENTS.md`](AGENTS.md) for the agent contract and
[`docs/PLAYBOOK.md`](docs/PLAYBOOK.md) for ready-made questions.
## Drift detection
```pwsh
./scripts/Compare-AzureSnapshots.ps1 -Old .\out-baseline -New .\out -OutFile .\drift.json
```
`drift.json` is deterministic and ignores volatile fields (`etag`,
`lastModifiedTime`, `provisioningState`). Each change is risk-tagged
(`breaking` / `risky` / `safe` / `review`) and feeds the **Drift Detective**
chat mode for a human-readable report.
## Security & privacy
- **Read-only by design.** No mutating Azure call is made — even with
`-IncludeSensitive`. The script never writes to Azure.
- **Secrets stay in Key Vault.** The dump captures Key Vault metadata and
RBAC, but **never** secret values. Even `-IncludeSensitive` only adds
what Azure already returns through `az` (App Settings, function keys,
connection strings as displayed by the platform).
- Files matching `*.SENSITIVE.json` are written **only** when
`-IncludeSensitive` is passed and are added to [`.gitignore`](.gitignore)
by default.
- Threat model and detailed handling: [`SECURITY.md`](SECURITY.md).
## Limitations
- `az group export` (ARM) caps at ~200 resources per RG and is not
guaranteed to be redeployable.
- Some services need extra calls beyond what the dump covers (historical
logs, runtime state). PRs welcome.
- If you lack permissions on a resource, the failure is captured in
`_errors.log` and the dump continues.
- Tenants with thousands of resources may need `-MaxParallel` tuning and a
long-running shell.
- Cross-tenant Lighthouse delegations are not modelled in the graph.
## Troubleshooting
| Symptom | Fix |
| --- | --- |
| `az` not on PATH after `winget install` | Restart the shell, or prepend the Azure CLI `wbin` folder to `PATH`. |
| `az login` MFA loop | `az logout` then `az login --tenant <tenantId>`. |
| `az graph query` hangs | Run `az extension add -n resource-graph` once. |
| Demo region has no SQL capacity | Pass `-SqlLocation northeurope` or another available region. |
| SQL re-deploy hits a soft-deleted server | The demo uses a hashed name to avoid this; otherwise wait or recover the server. |
| `_errors.log` non-empty | Open the file; usually missing RBAC. Add `Reader` and re-run. |
| HTML report won't open | Ensure `-GenerateReport` was passed, then re-run. |
## FAQ
**Is this safe to run in production?**
Yes. It only reads. Without `-IncludeSensitive` the dump never even asks
for app settings or connection strings.
**How long does a full dump take?**
A subscription with ~200 resources typically completes in **2–4 minutes** on
a developer laptop. Per-resource calls are parallelised (`-MaxParallel`).
**Why PowerShell instead of Python/Go?**
`az` already requires Python. PowerShell 7 is cross-platform, ships with
sorted-key JSON support out of the box, and lets the script stay
dependency-free.
**Can I run it from CI?**
Yes. Use a federated identity / service principal with `Reader`. The
included [GitHub Actions workflow](.github/workflows/ci.yml) lints the code
and validates schemas; an example "snapshot on schedule" workflow is on the
[roadmap](#roadmap).
**Can it dump multiple subscriptions?**
Run it once per subscription with different `-OutputDir`. Aggregating the
graph across subs is on the [roadmap](#roadmap).
**How do I customise what gets collected?**
[`lib/Collectors.ps1`](lib/Collectors.ps1) has one `Invoke-Phase-*` function
per phase. Add or skip phases by editing
[`Invoke-AzureSnapshot.ps1`](Invoke-AzureSnapshot.ps1)'s phase list. See
[CONTRIBUTING.md](CONTRIBUTING.md#adding-a-per-service-extractor).
**Does it support Azure Government / China?**
The dump uses whichever endpoint `az` is configured for, so yes — but it
hasn't been tested there. Reports welcome.
## Project layout
```text
.
├─ Invoke-AzureSnapshot.ps1 # entry point (13 phases)
├─ lib/
│ ├─ Common.ps1 # az wrapper, deterministic JSON, helpers
│ ├─ Collectors.ps1 # one Invoke-Phase-* per phase
│ ├─ Graph.ps1 # relationship graph + Mermaid generators
│ └─ Report.ps1 # self-contained HTML report
├─ demo/ # Bicep workload to validate the tool
├─ prompts/ # Copilot/MCP prompt files
├─ scripts/
│ └─ Compare-AzureSnapshots.ps1 # deterministic drift differ
├─ schemas/ # JSON Schemas for manifest, inventory, edges
├─ docs/
│ └─ PLAYBOOK.md # ready-made questions and workflows
├─ AGENTS.md # agent contract for any LLM-powered IDE
├─ .github/
│ ├─ chatmodes/ # specialized Copilot chat modes
│ ├─ ISSUE_TEMPLATE/ # bug + feature request forms
│ ├─ copilot-instructions.md
│ ├─ dependabot.yml
│ ├─ pull_request_template.md
│ └─ workflows/ci.yml
└─ .vscode/mcp.json # Azure MCP server registration
```
## Contributing
PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). The dump is
intentionally small and dependency-free; please preserve that. By
contributing you agree to abide by our
[Code of Conduct](CODE_OF_CONDUCT.md).
Security issues → see [SECURITY.md](SECURITY.md). Do not open public
issues for vulnerabilities.
Release notes → [CHANGELOG.md](CHANGELOG.md).
## Roadmap
- Multi-subscription / management-group aggregation.
- Resource Graph KQL query catalogue exposed as MCP tools.
- Optional cost roll-up driven by `azure_mcp.pricing`.
- "Snapshot on schedule" GitHub Action template.
- Optional Terraform reconstruction prompt (Bicep is the default).
## License
[MIT](LICENSE) © José María Flores Zazo.
Connection Info
You Might Also Like
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
servers
Model Context Protocol Servers
servers
Model Context Protocol Servers
Time
A Model Context Protocol server for time and timezone conversions.
Filesystem
Node.js MCP Server for filesystem operations with dynamic access control.