Skip to main content

Security License Lens

The security you already own (and ignore).

You pay for E5, Entra ID P2, Defender, and related SKUs. A lot of the useful controls in those SKUs never get turned on. LicenseLens maps what you own to the controls that should be on, then reports the gaps: you pay for X, we expected Y, we observed Z.

CLI: licenselens · Requires Python 3.12+

Documentation: d4rk-pri0r.github.io/licenselens

Sample report (dry-run): examples/sample-report/ — a scrubbed dry-run tenant.

Quick start

# One-command offline demo → HTML report (macOS / Linux / Windows)
pipx install licenselens
licenselens demo

# Interactive scan: prompts for anything missing (TTY)
licenselens scan

# Or jump straight to a live tenant walkthrough
licenselens quickstart

On Windows, the PyPI wheel bundles the PowerShell collector bridge since 0.4.0 (shipping in the 0.4.0 release; PyPI latest is 0.3.0 until it is published — see Releases), so the email pack and all PowerShell-only collectors run from a plain pipx install — see the Windows guide (requires Python 3.12+ and pipx).

Contributors: see contributing.md for the development setup.

In a terminal, licenselens scan asks demo vs live tenant, sign-in method, and other missing options. Flags and AZURE_* env vars always win when set. Non-interactive environments default to dry-run (or exit with a clear error on --live without credentials).

Default priority packs are identity + endpoint. They shape the headline rollup and top actions; enabled checks still evaluate unless --workload filters them. Email policy config is not readable via Graph (PowerShell-only); use --allow-email-proxy only if you explicitly want a labeled Secure Score degraded path.

Live / MSP

licenselens doctor --live --auth client_secret
licenselens scan --live --auth client_secret -o reports
licenselens batch tenants.yaml -o reports

What it looks like

One HTML file with posture, entitlements, ranked gaps, and an explore view of every assessed control. It runs with JavaScript off and does not make network requests.

report hero

The dashboard: what you own, what's working, and what to fix first.

report findings

Every finding shows its evidence and a direct link to the admin page.

The report on mobile
The same report at mobile width.

A concrete example

The most common finding, id-ca-priv-gaps:

  • You pay for Microsoft 365 E5, so Conditional Access is licensed for every user.
  • We expect MFA and legacy-auth blocking enforced through a CA policy.
  • We observed zero Conditional Access policies → the report marks the tenant EXPOSED.
  • Do this → enable an MFA CA policy (a few hours of work). The gap closes on the next scan.

Why Security License Lens?

Tool Optimizes for
ScubaGear CISA baseline compliance
Maester Continuous config tests (Pester)
Microsoft Secure Score Score + recommendations (not SKU-gated)
License waste scripts Seat assignment efficiency
Security License Lens Owned SKUs → expected high-value controls → unused/default gaps

See the documentation site for the full tool comparison.

Diff, discovery, and batch

# Compare two scan JSON artifacts by check_id
licenselens diff reports/before.json reports/after.json -o reports/diff.md

# Discover Sentinel-capable workspaces (prints ARM resource IDs)
licenselens discover-workspace --auth client_secret

# Multi-tenant scans from tenants.yaml (per-tenant reports + index.md)
licenselens batch tenants.yaml -o reports

Full check pack (v0.4.0)

166 checks · 31 capabilities · 11 profiles · 135 pinned SCuBA coverage rows (131 mapped) · package/sample 0.4.0

Checks run as direct, proxy, manual (you confirm), or dynamic (direct first, Secure Score only if direct is missing). The report still records whether a dynamic check ended up direct or proxy.

The authoritative pack lives in the generated reference (do not maintain a partial public table here):

Unlicensed capabilities report not_licensed instead of false gaps.

Known limitations

See limitations.md for the full list. Short version:

  • Email pack off by default — no Graph API for MDO policy config (PowerShell-only); --allow-email-proxy is opt-in and labeled (dynamic / Secure Score path)
  • Some surfaces are manual (operator-confirmed) or proxy (Secure Score); see the check reference for per-check state
  • Sentinel needs a workspace ARM ID + Azure RBAC
  • Sign-in / MDE inventories may truncate on huge tenants
  • Findings are advisory, not a compliance certification
  • No product telemetry by default

Architecture

SKUs / service plans → capability catalog → eligible checks
        → collectors (Graph / MDE / ARM) → findings → HTML / JSON / Markdown

Permissions

See permissions.md and app-registration.md.

Exit codes

Code Meaning
0 Success (no gap/partial findings)
1 Completed with gap or partial findings
2 Auth / configuration / API error

Contributing

See contributing.md and adding-a-check.md.

Security

security.md — read-only, no telemetry by default.

License

MIT

Disclaimer

Security License Lens is an independent open-source project and is not affiliated with, endorsed by, or sponsored by Microsoft Corporation. Findings are advisory. “Microsoft”, “Entra”, “Defender”, “Sentinel”, and “Purview” are trademarks of their respective owners.

Metadata

Release files for licenselens 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for licenselens 0.4.0
File Size Uploaded
licenselens-0.4.0.tar.gz 1.9 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for licenselens 0.4.0
File Interpreter ABI Platform
licenselens-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 2.9 MB

Release files / licenselens-0.4.0.tar.gz

Download URL licenselens-0.4.0.tar.gz
Size 1.9 MB
Tags Source
SHA-256 checksum
How to use checksums
667e32ae44eb77e964ddcc6f55d34c01623f331400a1279b0197dcdb82c0b673
BLAKE2b-256 checksum
How to use checksums
fd845742a130e779aed1f0b11512ec8230c12ccdcdfcdf6befe640543222e040
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release files / licenselens-0.4.0-py3-none-any.whl

Download URL licenselens-0.4.0-py3-none-any.whl
Size 958.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9e6090f11fa70b226f98c0ab46ddafdd8a72e0499e8f3f0f70644441af68b207
BLAKE2b-256 checksum
How to use checksums
280db313de2bb1fa1de7e29885589af10a43dae8e4c0eef5956926b6808e8c5b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page