SYNOPSIS
Lists every sharing link of one or more SharePoint Online sites, one row per link, using PnP.PowerShell app-only.SYNTAX
DESCRIPTION
Get-SPOSharingLinkReport is the file-level companion of Get-SPOSiteReport -IncludeSharingLinks: where the latter answers “which sites have an exposure worth looking at” with a per-site count, this function answers “which file is shared, with whom, until when, and through which URL” for the sites you point it at. It is deliberately not tenant-wide by default: the detail costs Microsoft Graph calls per shared item, so the intended workflow is to triage with Get-SPOSiteReport, then drill into the sites it flags. HOW THE SHARED ITEMS ARE FOUND A naive implementation walks every document library, loads HasUniqueRoleAssignments on every single item, and asks Graph for the links of the ones that have unique permissions. That is one round trip per file, which does not survive a real tenant. This function inverts the problem: SharePoint already materialises every sharing link as a hidden site group named ‘SharingLinks.<itemUniqueId>.<linkType>.<linkGuid>’, so a single Get-PnPGroup call per site yields the exact list of items that carry a link. Only those items are then resolved and queried. The cost is proportional to the number of shared items, not to the number of files in the site, which is usually several orders of magnitude smaller. Each candidate item is resolved from its unique ID through the REST endpoints /_api/web/GetFileById and, if that returns nothing, /_api/web/GetFolderById - an item is one or the other, and the group name does not say which. The links themselves are then read with Get-PnPFileSharingLink / Get-PnPFolderSharingLink, which is what provides the authoritative link type (the Graph ‘scope’ property), the expiration date, the password protection, the download block and the identities the link was shared with. The group name is used only as an index of what to look at, never as the source of truth for the link itself. TWO MODES, AND WHY THE DEFAULT AVOIDS GRAPH By default the function never calls Microsoft Graph. Everything it reports comes from the SharingLinks groups themselves: the shared item (resolved through SharePoint REST), the link type read from the group name, and - the part that matters most for an access audit - the people the link was shared with, who are literally the members of that group. This runs with the SharePoint Sites.FullControl.All permission the rest of the module already needs, and nothing more. IncludeGraphDetails adds what only Graph knows: the link URL, the expiration date, the password protection, the download block, the role granted, and the authoritative scope of a Flexible link. That costs one Graph call per shared item AND the Microsoft Graph APPLICATION permissions Files.Read.All and Sites.Read.All - which mean “read every file of the tenant, with no user behind the call”. On a production tenant that is a decision worth making deliberately, not a checkbox: consider Sites.Selected instead, which scopes the app to the sites you explicitly grant it. WHAT THE DEFAULT MODE CANNOT TELL YOU A link type of ‘Flexible’ is reported as Flexible, never as ‘SpecificPeople’. Flexible is the modern SharePoint link model where the scope is set per link, so the group name genuinely does not say whether such a link is restricted to named people or open to anyone holding it. Guessing here would be actively harmful: reporting a Flexible link as ‘SpecificPeople’ makes SharingLinksAnyoneCount read as zero on a site that may well have an anonymous link. When that distinction matters, IncludeGraphDetails is the only way to resolve it - the shared-with list of the default mode is often enough to conclude on its own. PERMISSIONS- Default mode: SharePoint (Office 365 SharePoint Online) Sites.FullControl.All application permission, the same one Get-SPOSiteReport uses. No Graph permission at all.
- IncludeGraphDetails: the above, plus the Microsoft Graph APPLICATION permissions Files.Read.All and Sites.Read.All. These are a different Entra resource - consenting to the SharePoint one does not cover Graph. Without them every item fails at the last step with ‘accessDenied 403’ (Graph token present but insufficient) or ‘Either scp or roles claim need to be present in the token’ (no Graph permission on the certificate at all). After granting consent, allow a few minutes for propagation and reconnect: PnP caches the acquired token.