Private/Invoke-GalleryAPI.ps1

function Invoke-GalleryAPI {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$ModuleName
    )

    $baseUri = "https://www.powershellgallery.com/api/v2/FindPackagesById()?id='$ModuleName'"
    $allEntries = [System.Collections.Generic.List[PSObject]]::new()
    $uri = $baseUri

    do {
        try {
            $rawResp = Invoke-WebRequest -Uri $uri -UseBasicParsing -ErrorAction Stop
        } catch {
            Write-Warning "Failed to query PowerShell Gallery for '$ModuleName': $($_.Exception.Message)"
            break
        }

        $nextUri = $null

        # Parse entries via Invoke-RestMethod (auto-parses OData XML)
        try {
            $response = [xml]$rawResp.Content
        } catch {
            Write-Warning "Failed to parse Gallery response for '$ModuleName'."
            break
        }

        $entries = @($response.feed.entry)
        foreach ($entry in $entries) {
            $props = $entry.properties
            if ($null -eq $props) { continue }

            $allEntries.Add([PSCustomObject]@{
                Id                   = $props.Id
                Version              = $props.Version
                DownloadCount        = [long]$props.DownloadCount.'#text'
                VersionDownloadCount = [long]$props.VersionDownloadCount.'#text'
                Published            = [datetime]$props.Published.'#text'
                IsLatestVersion      = $props.IsLatestVersion.'#text' -eq 'true'
                IsPrerelease         = $props.IsPrerelease.'#text' -eq 'true'
                Authors              = $props.Authors
            })
        }

        # Check for OData pagination via <link rel="next">
        if ($rawResp.Content -match '<link\s+rel="next"\s+href="([^"]+)"') {
            $nextUri = [System.Net.WebUtility]::HtmlDecode($Matches[1])
        }
        $uri = $nextUri

    } while ($null -ne $uri)

    return $allEntries
}