Getting started¶
Install¶
# Windows primary install — pipx from PyPI (real today)
# Prerequisites: Python 3.12+ (python.org or the Microsoft Store) and pipx
# (py -m pip install --user pipx; then make sure pipx's bin dir is on PATH)
pipx install licenselens
licenselens demo # offline demo → HTML report
# or: licenselens quickstart
The 0.4.0 wheel includes the PowerShell collector bridge, so email and the
other PowerShell-only packs work from a normal pipx install. Needs Python
3.12+ and pipx. See the Windows guide.
The standalone per-user installer is in that guide too; it is not published
yet. Do not run irm … | iex.
Optional docs/release helpers (not required for day-to-day use) may be run with
uv run when those tools are installed — for example scripts/docs-check.sh and
scripts/release_gate.py.
Dry-run scan¶
licenselens version
licenselens checks
licenselens plan --demo
licenselens scan --dry-run -o reports
# or, in a terminal with no flags: choose "Demo sample data" when prompted
licenselens scan
Open reports/security-license-lens-report.html in a browser. Single-tenant
scan / demo / quickstart write report files flat into -o (default
reports).
Preview the execution plan before your first live scan:
Interactive scan (prompts)¶
In an interactive terminal, licenselens scan walks you through missing options:
- Demo sample data vs your Microsoft tenant
- Sign-in method (device code, app secret, or Azure CLI)
- Tenant / app credentials if needed
- Output folder, open HTML, optional Sentinel workspace, optional preflight
Flags and environment variables always override prompts. In CI or pipes (no TTY),
the command does not hang: default is dry-run, and --live without credentials
exits with a short message listing what to set.
Quick demo¶
Runs the offline demo tenant, prints the executive summary to the terminal, writes the HTML report, and optionally opens it in your browser. The report is from curated demo data — not a real tenant.
Docker¶
Run the offline demo in a container and collect reports via a mounted volume:
docker build -t licenselens .
mkdir -p reports
docker run --rm -v "$PWD/reports:/reports" licenselens
# or explicitly:
docker run --rm -v "$PWD/reports:/reports" licenselens demo -o /reports
licenselens is the image entrypoint, so any command works:
docker run --rm -v "$PWD/reports:/reports" licenselens scan --live --auth device -o /reports
docker run --rm licenselens version
docker run --rm licenselens checks
Note:
--auth deviceneeds an interactive terminal; add-it:docker run --rm -it -v "$PWD/reports:/reports" licenselens scan --live --auth device -o /reports
Sample report¶
A scrubbed dry-run report is committed at examples/sample-report/ so you can
preview HTML output without a tenant.
Open the interactive sample report
Compare two scans (diff)¶
Run a scan, apply a fix, re-run, then diff the two JSON artifacts:
licenselens scan -o reports/before
# Apply a fix, then scan into a different directory.
licenselens scan -o reports/after
licenselens diff \
reports/before/security-license-lens-report.json \
reports/after/security-license-lens-report.json \
-o reports/diff.md
The diff groups checks into new gaps, resolved, improved, worsened
and unchanged, and lists confidence changes. Use -o diff.json for a machine-readable
version.
Discover a Sentinel workspace¶
Instead of pasting an ARM resource ID, let the tool find Sentinel-capable workspaces:
Pass --subscription-id to limit the search or --max-subscriptions to cap it.
The command prints one workspace ARM resource ID per line; use one with
scan --workspace-resource-id or with the discover_workspaces: true batch option.
Batch multi-tenant scans (MSPs)¶
Create a tenants.yaml listing each tenant, then run one batch:
tenants:
- slug: contoso
tenant_id: 11111111-1111-1111-1111-111111111111
auth_mode: client_secret # optional per tenant
workspace_resource_id: "" # optional
discover_workspaces: true # auto-find a single Sentinel workspace
- slug: fabrikam
tenant_id: 22222222-2222-2222-2222-222222222222
Per-tenant reports land under reports/<slug>/<timestamp>/ and a summary
index.md is written next to them. A failing tenant is recorded in the index
and the batch continues. See MSP batch for the full key set.
Live scan (identity pack)¶
- Register an app and grant admin consent — app-registration.md
- Preflight:
export AZURE_TENANT_ID=...
export AZURE_CLIENT_ID=...
export AZURE_CLIENT_SECRET=...
licenselens doctor --live --auth client_secret
On doctor, --profile is probe depth (basic default, or full).
--profile full also probes the Defender for Endpoint API and, when you pass
--workspace-resource-id, the Sentinel workspace:
licenselens doctor --live --auth client_secret --profile full \
--workspace-resource-id "/subscriptions/.../resourceGroups/.../providers/Microsoft.OperationalInsights/workspaces/..."
Profile ids on doctor use --assessment-profile (repeatable), not
--profile.
- Scan (on
scan/demo/quickstart,--profileis a profile id):
Interactive alternative:
licenselens scan --live --auth device \
--tenant-id "$AZURE_TENANT_ID" \
--client-id "$AZURE_CLIENT_ID" \
-o reports
Exit codes¶
| Code | Meaning |
|---|---|
| 0 | Success (no gap/partial findings) |
| 1 | Completed with gap or partial findings |
| 2 | Auth/config/Graph error |
Full flag catalog¶
Every command, flag, auth mode, and environment variable is listed in the CLI reference.