Private/Get-SiteSharingLink.ps1
|
function Get-SiteSharingLink { <# The engine, for one already-connected site. Discover which files have links via the SharingLinks groups, resolve those to paths, then pull the real link data per file and score it. Assumes Connect-PnPOnline has already run for this site. #> param( [Parameter(Mandatory)] [string] $SiteUrl, [switch] $IncludeFolders ) # 1. discovery - one call, only the files that actually have links $linkGroups = Invoke-WithRetry -Because 'group enumeration' -Action { Get-PnPGroup | Where-Object { $_.Title -like 'SharingLinks.*' } } if (-not $linkGroups) { return } $guids = $linkGroups | ForEach-Object { ($_.Title -split '\.')[1] } | Select-Object -Unique Write-Verbose "$SiteUrl : $(@($guids).Count) file(s) with sharing links." # 2. resolve GUIDs to file paths in one pass $map = Resolve-FileRefMap -NeededGuids $guids $siteTitle = (Invoke-WithRetry -Because 'Get-PnPWeb' -Action { Get-PnPWeb }).Title # 3. enrich per file with the real link data foreach ($guid in $guids) { $entry = $map[$guid.ToLower()] if (-not $entry) { Write-Warning "Link exists for GUID $guid but its file could not be resolved (deleted, or in a list this pass did not cover)." continue } if ($entry.IsFolder -and -not $IncludeFolders) { continue } # Folder links come from a different cmdlet than file links. $links = Invoke-WithRetry -Because "sharing links on $($entry.FileName)" -Action { if ($entry.IsFolder) { Get-PnPFolderSharingLink -Folder $entry.FileRef -ErrorAction SilentlyContinue } else { Get-PnPFileSharingLink -Identity $entry.FileRef -ErrorAction SilentlyContinue } } foreach ($link in $links) { # Under StrictMode a null Link would make every $lk.* below throw, so # skip a link that somehow has no Link facet rather than crash the run. $lk = $link.Link if (-not $lk) { Write-Warning "A link on $($entry.FileName) had no Link data; skipped." continue } $granted = $link.GrantedToIdentitiesV2 $recipients = if ($granted) { ($granted | ForEach-Object { $u = $_.User if ($u -and $u.Email) { $u.Email } elseif ($u -and $u.DisplayName) { $u.DisplayName } else { '(unknown)' } }) -join '; ' } elseif ($lk.Scope -eq 'Organization') { 'Everyone in the organisation' } elseif ($lk.Scope -eq 'Anonymous') { 'Anyone with the link' } else { '(none resolved)' } [pscustomobject]@{ SiteUrl = $SiteUrl SiteTitle = $siteTitle ItemType = if ($entry.IsFolder) { 'Folder' } else { 'File' } ItemName = $entry.FileName ItemPath = $entry.FileRef Label = $entry.Label Scope = $lk.Scope # Anonymous | Organization | Users Access = $lk.Type # View | Edit Recipients = $recipients Expiration = $link.ExpirationDateTime HasPassword = $link.HasPassword BlocksDownload = $lk.PreventsDownload RiskLevel = Get-LinkRisk $lk.Scope $lk.Type $link.ExpirationDateTime $link.HasPassword WebUrl = $lk.WebUrl LinkId = $link.Id } } } } |