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
            }
        }
    }
}