PowerShell module that builds a permission matrix for SharePoint Online — for a single site or all sites of a tenant — and renders it as a self-contained, interactive HTML report (no server needed, can be sent by mail).
Scan and rendering are separated by a JSON data model: the same scan can be rendered multiple times, versioned, and compared later (delta reports planned).
┌─────────────────────┐ JSON ┌──────────────────────┐
│ Scanner │ ─────────────► │ Renderer │
│ Invoke-SPPermission-│ │ New-SPPermission- │
│ Scan │ │ Report │
│ (PnP.PowerShell) │ │ (HTML, standalone) │
└─────────────────────┘ └──────────────────────┘
- Single site or whole tenant (
-SiteUrl/-AllSites), configurable depth:-Depth 0= site only,1= + document libraries,2= + first folder level, … - Complete output, cheap scan: every row shows effective permissions, but role
assignments are only loaded where inheritance is actually broken
(
HasUniqueRoleAssignments) — everything else is derived from the parent. - Inherited vs. unique: inherited permissions are dimmed, broken inheritance is highlighted — the audit question "where does it deviate?" is answered at a glance.
- Transitive group resolution: SharePoint groups → nested Entra ID groups → members,
resolved via Graph (
Invoke-PnPGraphMethod, no extra Graph module) with visible nesting and a scan-wide group cache. - Sharing-link analysis: link groups (
SharingLinks.*shadow permissions) are detected and classified - a dedicated report tab shows scope (specific people / organization-wide / anyone), risk, access level, affected folders and the people behind every link; Limited Access noise is filtered out. - Excel export (
Export-SPPermissionMatrix): the same matrix as an .xlsx workbook (groups and/or people view, colored cells, frozen panes) - requires the ImportExcel module. - Interactive HTML report with two views:
- Groups & roles: collapsible hierarchy tree, principals as columns (SharePoint
groups → Entra groups → users → sharing links),
FC/W/C/Rcell abbreviations (custom levels as footnotes), member count per column, group member drill-down. - Persons (effective): columns are resolved individual people; each cell shows the highest effective permission, access via group membership is marked and one click reveals the derivation chain ("B via owners group → nested Entra group").
- Search/filter including the reverse question "where does person X have access?", row/column crosshair, key-figure chips, tenant overview page with per-site figures.
- Groups & roles: collapsible hierarchy tree, principals as columns (SharePoint
groups → Entra groups → users → sharing links),
- Throttling-safe: HTTP 429/503 retries honoring
Retry-After— required for tenant scans.
- PowerShell 7.4+ (current PnP.PowerShell versions do not run on Windows PowerShell 5.1)
- PnP.PowerShell 3.x (installed automatically as a dependency)
- An Entra app registration (PnP.PowerShell no longer ships a default client) — see setup below
Install-Module SPPermissionMatrix -Scope CurrentUserCreates an Entra app registration with certificate (app-only, unattended capable) and the
required permissions (SharePoint Sites.FullControl.All, Graph Directory.Read.All):
Register-SPPermissionApp -Tenant contoso.onmicrosoft.comFor testing, an interactive login with an existing app registration is enough
(-Interactive below).
# Single site, down to the first folder level
Invoke-SPPermissionScan -SiteUrl https://contoso.sharepoint.com/sites/hr -Depth 2 `
-ClientId $appId -Interactive -OutputPath .\hr.json
# Whole tenant, unattended (certificate)
Invoke-SPPermissionScan -AllSites -TenantAdminUrl https://contoso-admin.sharepoint.com -Depth 1 `
-ClientId $appId -Tenant contoso.onmicrosoft.com -CertificatePath .\SPPermissionMatrix.pfx `
-OutputPath .\tenant.jsonNew-SPPermissionReport -InputPath .\hr.json -Open
# or as a pipeline:
Invoke-SPPermissionScan -SiteUrl $url -Depth 2 -ClientId $appId -Interactive |
New-SPPermissionReport -OpenInstall-Module ImportExcel -Scope CurrentUser # one-time
Export-SPPermissionMatrix -InputPath .\hr.json -View Both -OpenCompare-SPPermissionScan -ReferencePath .\scan_old.json -DifferencePath .\scan_new.json -OpenReports new/removed inheritance breaks, added/removed/changed permission assignments, new folders, new/removed sharing links and group membership changes (people added to or removed from groups, resolved transitively).
examples/Invoke-ScheduledScan.ps1 is a ready-to-use
runbook for Task Scheduler or Azure Automation: it scans with certificate auth, archives
a timestamped JSON, renders the report, compares against the previous scan and can mail
both files via Microsoft Graph (requires the additional Graph application permission
Mail.Send).
| Cell | Meaning |
|---|---|
FC |
Full Control |
W |
Write (SharePoint level "Edit") |
C |
Contribute |
R |
Read |
X1, X2, … |
Custom permission levels (footnotes below the matrix) |
| dimmed | inherited from parent |
| highlighted row | unique permissions — inheritance is broken here |
| ⚠ | auto-generated sharing-link group |
- ✅ MVP: single-site scanner with
-Depth, JSON output, HTML report with matrix and group drill-down - ✅ Tenant scan (
-AllSites), throttling handling, overview page - Excel export (internal v/ä/l style), deeper sharing-link analysis
- Scan comparison (delta report), scheduled per-customer runs
MIT — © 2026 Flurin Gubler