Skip to main content

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.
Client secrets are not supported by SharePoint for app-only: a certificate is mandatory. Provide it through CertificateThumbprint (Windows certificate store), CertificatePath (.pfx file) or CertificateBase64Encoded (base64 string, handy for Azure Automation or a pipeline variable). Sites are processed in parallel (ForEach-Object -Parallel) with one PnP connection per site. Tune the concurrency with ThrottleLimit. PowerShell 7 is required.

EXAMPLES

EXAMPLE 1

Lists every sharing link of a single site.

EXAMPLE 2

The intended workflow: triage the whole tenant with the cheap per-site counts, then get the file-level detail of the anonymous links only on the sites that actually have one.

EXAMPLE 3

Exports every link that will never expire on the given sites to an Excel file in the user profile directory.

PARAMETERS

-ClientId

(Mandatory) Application (client) ID of the Entra app registration used for the app-only connection.

-Tenant

(Mandatory) Tenant domain name for the PnP connection, for example contoso.onmicrosoft.com. Used by Connect-PnPOnline (it expects the domain, not the tenant GUID).

-CertificateThumbprint

Thumbprint of the certificate located in the current user’s Windows certificate store. Provide exactly one of CertificateThumbprint, CertificatePath or CertificateBase64Encoded.

-CertificatePath

Path to a local .pfx certificate file. Use CertificatePassword when the file is protected. Provide exactly one of CertificateThumbprint, CertificatePath or CertificateBase64Encoded.

-CertificatePassword

(Optional) SecureString password protecting the .pfx file passed to CertificatePath.

-CertificateBase64Encoded

Base64-encoded certificate (with its private key) passed directly to Connect-PnPOnline. Provide exactly one of CertificateThumbprint, CertificatePath or CertificateBase64Encoded.

-SiteUrl

(Mandatory) One or more site collection URLs to scan. Accepts pipeline input, by value or by the Url property, so the output of Get-SPOSiteReport can be piped straight in (its Url column binds to this parameter through its alias).

-IncludeGraphDetails

(Optional) Re-reads every link through Microsoft Graph to add the link URL, the expiration date, the password protection, the download block, the granted role, and the real scope of a Flexible link. Requires the Microsoft Graph Files.Read.All and Sites.Read.All application permissions - see the PERMISSIONS section above before turning this on against a production tenant. Without it, the report carries LinkType/LinkTypeRaw, SharedWith, the item, and the SharingLinks group it came from. With it, those Graph columns are added and the type is resolved. Columns that were not collected are absent rather than empty, so an empty cell always means the data really is empty.

-LinkType

(Optional) Restricts the output to one or more link types: Anyone (anonymous ‘Anyone with the link’), Company (people in the organization), Flexible (modern link whose scope is only resolvable through Graph), SpecificPeople (requires IncludeGraphDetails), or Other for a type this function does not know about yet. Filtering happens after collection, so it does not make the run faster - it only makes the report shorter.

-ExpiredOnly

(Optional) Keeps only the links whose expiration date is in the past. Requires IncludeGraphDetails: expiration dates only exist in the Graph payload. Mutually exclusive with NeverExpiringOnly and ExpiringInDays.

-NeverExpiringOnly

(Optional) Keeps only the links that carry no expiration date at all. Requires IncludeGraphDetails. Mutually exclusive with ExpiredOnly and ExpiringInDays.

-ExpiringInDays

(Optional) Keeps only the links expiring within that many days from now, excluding those already expired. Requires IncludeGraphDetails. Mutually exclusive with ExpiredOnly and NeverExpiringOnly.

-ThrottleLimit

(Optional) Number of sites processed concurrently. Defaults to 8. Lower it if SharePoint starts answering 429: past a certain rate, more concurrency means more throttling and a longer total run.

-ExportToExcel

(Optional) Exports the result to an .xlsx file instead of returning the objects to the pipeline.

-ExportPath

(Optional) Output directory for the Excel export. Defaults to the user profile directory.

CommonParameters

This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see about_CommonParameters.

INPUTS

OUTPUTS

NOTES

https://ps365.clidsys.com/docs/commands/Get-SPOSharingLinkReport