Public/Get-PSUADOPullRequestInventory.ps1

function Get-PSUADOPullRequestInventory {
    [CmdletBinding()]
    param (
        [Parameter()]
        [string]$Organization = $env:ORGANIZATION,

        [Parameter()]
        [string]$PAT = $env:PAT,

        [Parameter()]
        [string[]]$Project = @('Technical Services'),

        [Parameter()]
        [string]$OutputFilePath,

        [Parameter()]
        [ValidateRange(1, 50)]
        [int]$ThrottleLimit = 10,

        [Parameter()]
        [ValidateRange(1, 60)]
        [int]$TimeoutMinutes = 10
    )

    Write-Host "📢 Fetching projects for organization '$Organization'..."
    Write-Host "🧵 Starting parallel collection with Start-ThreadJob (ThrottleLimit = $ThrottleLimit)"

    $results = [System.Collections.Generic.List[PSCustomObject]]::new()
    $allJobs = @()

    foreach ($proj in $Project) {
        $repos = Get-PSUADORepositories -Project $proj -Organization $Organization -PAT $PAT

        foreach ($repo in $repos) {
            $job = Start-ThreadJob -ScriptBlock {
                param ($projectName, $repoName, $org, $pat)

                Import-Module OMG.PSUtilities.AzureDevOps -Force

                $prs = Get-PSUADOPullRequests -Project $projectName -Repository $repoName -Organization $org -PAT $pat
                return $prs
            } -ArgumentList $proj, $repo.name, $Organization, $PAT

            $allJobs += $job

            # Throttle if needed
            while (@($allJobs | Where-Object { $_.State -eq 'Running' }).Count -ge $ThrottleLimit) {
                Start-Sleep -Seconds 1
            }
        }
    }

    # Wait for all jobs to complete or timeout
    $jobTimeout = [datetime]::Now.AddMinutes($TimeoutMinutes)
    while (($allJobs | Where-Object { $_.State -eq 'Running' }).Count -gt 0) {
        if ([datetime]::Now -gt $jobTimeout) {
            Write-Warning "⚠️ Timeout reached. Stopping remaining jobs."
            $allJobs | Where-Object { $_.State -eq 'Running' } | ForEach-Object { Stop-Job $_ }
            break
        }
        Start-Sleep -Seconds 2
    }

    # Collect results
    foreach ($job in $allJobs) {
        try {
            $output = Receive-Job -Job $job -ErrorAction Stop
            if ($output) {
                foreach ($pr in $output) {
                    $results.Add($pr)
                }
            }
        }
        catch {
            Write-Warning "⚠️ Job [$($job.Id)] failed: $_"
        }
        finally {
            Remove-Job -Job $job -Force
        }
    }

    Write-Host "✅ Collected $($results.Count) pull requests."

    if ($OutputFilePath) {
        try {
            $results | Export-Csv -Path $OutputFilePath -NoTypeInformation -Encoding UTF8
            Write-Host "💾 Saved to: $OutputFilePath"
        }
        catch {
            Write-Warning "❌ Failed to export results to $OutputFilePath : $_"
        }
    }

    return $results
}