Public/Get-PSUk8sPodLabel.ps1

function Get-PSUk8sPodLabel{
    <#
    .SYNOPSIS
    Gets pod labels from AKS clusters in parallel with minimal kubectl overhead.
 
    .DESCRIPTION
    Retrieves pod labels from all namespaces in AKS clusters using a single optimized kubectl call per cluster.
    Shows live job progress and lists failed clusters for easy retry.
    Clusters are retrieved from the local kubeconfig file (~/.kube/config).
    Ensure all required cluster credentials are updated in the kubeconfig file before running.
 
    .PARAMETER ClusterFilter
    Optional. Only process clusters whose names match this filter (wildcards supported).
 
    .PARAMETER ThrottleLimit
    Maximum number of jobs to run in parallel.
 
    .EXAMPLE
    Get-PSUk8sPodLabel -ClusterFilter "*prod*" -ThrottleLimit 15
    #>


    [CmdletBinding()]
    param(
        [string]$ClusterFilter = "*",
        [int]$ThrottleLimit = 8
    )

    try {
        $kubeConfigPath = Join-Path $env:USERPROFILE ".kube\config"

        Write-Host "Note: Retrieving clusters from kubeconfig: $kubeConfigPath" -ForegroundColor Cyan
        Write-Host " Ensure all required cluster credentials are updated in the kubeconfig file before running." -ForegroundColor Yellow

        if (-not (Test-Path $kubeConfigPath)) {
            Write-Error "Kubeconfig file not found at $kubeConfigPath."
            return
        }

        Write-Verbose "Getting all available clusters..."
        $clusters = kubectl config get-contexts -o name | Where-Object { $_ -like '*-admin' }
        if ($ClusterFilter -and $ClusterFilter -ne "*") {
            $clusters = $clusters | Where-Object { $_ -like $ClusterFilter }
        }
        if (-not $clusters) {
            Write-Warning "No Kubernetes clusters found in kubeconfig."
            return
        }

        Write-Host "Processing $($clusters.Count) clusters in parallel (ThrottleLimit: $ThrottleLimit)..."

        $jobs = @()
        foreach ($cluster in $clusters) {
            while (($jobs | Where-Object { $_.State -eq 'Running' }).Count -ge $ThrottleLimit) {
                $completed = ($jobs | Where-Object { $_.State -eq 'Completed' }).Count
                $running   = ($jobs | Where-Object { $_.State -eq 'Running' }).Count
                $failed    = ($jobs | Where-Object { $_.State -eq 'Failed' }).Count
                $percent   = [math]::Round(($completed / $clusters.Count) * 100, 1)

                $color = if ($percent -lt 50) { "Yellow" } elseif ($percent -lt 91) { "Cyan" } else { "Green" }
                Write-Host ("`rJobs completed: {0} / {1} ({4,5}%) | Running: {2} | Failed: {3} " -f $completed, $clusters.Count, $running, $failed, $percent) -ForegroundColor $color -NoNewline

                Start-Sleep -Seconds 1
            }

            $jobs += Start-ThreadJob -Name $cluster -ArgumentList $cluster -ScriptBlock {
                param($cluster)
                try {
                    $output = kubectl --context $cluster get pods --all-namespaces `
                        -o jsonpath='{range .items[*]}{.metadata.namespace}{"|"}{.metadata.name}{"|"}{.metadata.labels}{"|"}{.status.phase}{"|"}{.metadata.creationTimestamp}{"\n"}{end}' 2>$null

                    $lines = $output -split "`n"
                    foreach ($line in $lines) {
                        if (-not $line) { continue }
                        $parts = $line -split '\|', 5
                        [PSCustomObject]@{
                            Cluster   = $cluster
                            Namespace = $parts[0]
                            PodName   = $parts[1]
                            Labels    = $parts[2] -replace '^map\[|\]$', '' -replace ' ', ','  | ConvertFrom-Json
                            Status    = $parts[3]
                            CreatedAt = [datetime]$parts[4]
                        }
                    }
                }
                catch {
                    Write-Error "Failed to process cluster '$cluster': $_"
                }
            }
        }

        # Wait for completion with progress
        $totalJobs = $jobs.Count
        while ($true) {
            $completed = ($jobs | Where-Object { $_.State -eq 'Completed' }).Count
            $running   = ($jobs | Where-Object { $_.State -eq 'Running' }).Count
            $failed    = ($jobs | Where-Object { $_.State -eq 'Failed' }).Count
            $percent   = [math]::Round(($completed / $totalJobs) * 100, 1)

            $color = if ($percent -lt 50) { "Yellow" } elseif ($percent -lt 91) { "Cyan" } else { "Green" }
            Write-Host ("`rJobs completed: {0} / {1} ({4,5}%) | Running: {2} | Failed: {3} " -f $completed, $totalJobs, $running, $failed, $percent) -ForegroundColor $color -NoNewline

            if ($completed + $failed -eq $totalJobs) { break }
            Start-Sleep -Seconds 1
        }
        Write-Host "" # Newline after loop

        # Gather results
        $allResults = @()
        $failedClusters = @()
        foreach ($job in $jobs) {
            if ($job.State -eq 'Completed') {
                $result = Receive-Job -Job $job
                if ($result) { $allResults += $result }
            }
            elseif ($job.State -eq 'Failed') {
                $failedClusters += $job.Name
            }
            Remove-Job -Job $job
        }

        # Summary
        if ($failedClusters.Count -gt 0) {
            Write-Host "Failed clusters: $($failedClusters -join ', ')" -ForegroundColor Red
        }
        else {
            Write-Host "All clusters processed successfully." -ForegroundColor Green
        }

        if (-not $allResults) {
            Write-Warning "No pods found in any cluster."
            return
        }

        Write-Host "Found $($allResults.Count) pods across $($clusters.Count) clusters" -ForegroundColor Green
        return $allResults

    }
    catch {
        $PSCmdlet.ThrowTerminatingError($_)
    }
}