Private/Save-KubeSnapshot.ps1

function Save-KubeSnapshot {
    param (
        [string]$Namespace,
        [switch]$ClusterResources,
        [switch]$AllNonSystemNamespaces,
        [string]$Labels,
        [string]$OutputPath,
        [switch]$DryRun,
        [string]$Objects # Accept comma-separated list of objects
    )

    # Import the PowerShell-YAML module if not already loaded
    if (-not (Get-Module -ListAvailable -Name powershell-yaml)) {
        Import-Module powershell-yaml
    }

    # Function to run kubectl command and return output
    function Invoke-KubectlCommand {
        param ([string]$command)
        $processInfo = New-Object System.Diagnostics.ProcessStartInfo
        $processInfo.FileName = "kubectl"
        $processInfo.Arguments = $command
        $processInfo.RedirectStandardOutput = $true
        $processInfo.RedirectStandardError = $true
        $processInfo.UseShellExecute = $false
        $processInfo.CreateNoWindow = $true

        $process = New-Object System.Diagnostics.Process
        $process.StartInfo = $processInfo
        $process.Start() | Out-Null

        $output = $process.StandardOutput.ReadToEnd()
        $stderr = $process.StandardError.ReadToEnd()
        $process.WaitForExit()

        if ($stderr) {
            Write-Host "Error running kubectl command: $stderr" -ForegroundColor Red
        }

        return $output
    }

    # Function to save CRD instances
    function Save-CRDInstances {
        param (
            [string]$crdName,
            [string]$crdInstancesOutput,
            [string]$OutputPath,
            [string]$Scope, # "Cluster" or "Namespaced"
            [string]$Namespace = "" # Optional namespace for namespaced CRDs
        )
        if (-not $crdInstancesOutput -or $crdInstancesOutput -match "items: \[\]") {
            Write-Verbose "No instances found for $Scope-scoped CRD: $crdName"
            return
        }

        $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
        $scopedLabel = $Scope.ToLower()
        $namespaceLabel = if ($Namespace) { "_${Namespace}" } else { "" }
        $crdFile = Join-Path -Path $OutputPath -ChildPath "${crdName}${namespaceLabel}_${scopedLabel}_instances_${timestamp}.yaml"
        $crdInstancesOutput | Out-File -FilePath $crdFile -Force
        Write-Host "$Scope-scoped CRD instances of '$crdName' saved to: $crdFile" -ForegroundColor Green
    }

    # Define resource kinds
    $namespacedResources = @(
        "deployments", 
        "daemonsets", 
        "statefulsets", 
        "configmaps", 
        "secrets", 
        "services", 
        "ingresses", 
        "persistentvolumeclaims", 
        "horizontalpodautoscalers", 
        "roles", 
        "rolebindings", 
        "serviceaccounts", 
        "cronjobs", 
        "jobs", 
        "networkpolicies", 
        "poddisruptionbudgets", 
        "resourcequotas", 
        "limitranges"
    )

    $clusterScopedResources = @(
        "persistentvolumes", 
        "clusterroles", 
        "clusterrolebindings", 
        "namespaces",
        "customresourcedefinitions"
    )

    # Namespace configuration
    if ($ClusterResources) {
        $namespaceOption = "--all-namespaces"
    } elseif ($AllNonSystemNamespaces) {
        $namespaces = Invoke-KubectlCommand "get namespaces -o json" | ConvertFrom-Json
        $nonSystemNamespaces = $namespaces.items | Where-Object { $_.metadata.name -notmatch "^(kube-system|kube-public|kube-node-lease|default)$" } | Select-Object -ExpandProperty metadata | Select-Object -ExpandProperty name
    } elseif ($Namespace) {
        $namespaceCheck = Invoke-KubectlCommand "get namespace $Namespace" 2>$null
        if (-not $namespaceCheck) {
            Write-Host "Namespace '$Namespace' does not exist in the cluster." -ForegroundColor Red
            return
        }
        $namespaceOption = "-n $Namespace"
    } else {
        $namespaceOption = ""
    }

    if ($Labels) {
        $labelOption = "-l $Labels"
    } else {
        $labelOption = ""
    }

    if (-not $DryRun) {
        try {
            # Function to process namespaced resources
            function Process-Namespace {
                param ([string]$Namespace)
                foreach ($resource in $namespacedResources) {
                    $kubectlCmd = "get $resource -n $Namespace $labelOption -o json"
                    Write-Verbose "Running command: kubectl $kubectlCmd"
                    $resourceOutput = Invoke-KubectlCommand $kubectlCmd

                    if (-not $resourceOutput -or $resourceOutput -match '"items": \[\]') {
                        Write-Verbose "No $resource found in namespace $Namespace. Skipping."
                        continue
                    }

                    $resourceOutputJson = $resourceOutput | ConvertFrom-Json
                    foreach ($item in $resourceOutputJson.items) {
                        $resourceName = $item.metadata.name
                        $kind = $item.kind
                        $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
                        $safeResourceName = $resourceName -replace "[:\\/]", "_"
                        $resourceFile = Join-Path -Path $OutputPath -ChildPath "${kind}_${safeResourceName}_$timestamp.yaml"
                        $item | ConvertTo-Yaml | Out-File -FilePath $resourceFile -Force
                        Write-Host "Saved $kind '$resourceName' in namespace '$Namespace': $resourceFile" -ForegroundColor Green
                    }
                }

                # Process namespaced CRDs
                $crds = Invoke-KubectlCommand "get crds -o json" | ConvertFrom-Json
                if ($crds) {
                    foreach ($crd in $crds.items) {
                        $crdName = $crd.metadata.name
                        if ($crd.spec.scope -eq "Namespaced") {
                            $kubectlCmd = "get $crdName -n $Namespace -o yaml"
                            Write-Verbose "Running command for namespaced CRD instances: kubectl $kubectlCmd"
                            $crdInstancesOutput = Invoke-KubectlCommand $kubectlCmd
                            Save-CRDInstances -crdName $crdName -crdInstancesOutput $crdInstancesOutput -OutputPath $OutputPath -Scope "Namespaced" -Namespace $Namespace
                        }
                    }
                }
            }

            # Process each namespace
            if ($AllNonSystemNamespaces) {
                foreach ($ns in $nonSystemNamespaces) {
                    Write-Host "Processing namespace: $ns"
                    Process-Namespace -Namespace $ns
                }
            } elseif ($Namespace) {
                Write-Host "Processing namespace: $Namespace"
                Process-Namespace -Namespace $Namespace
            }

            # Cluster-scoped resources
            if ($ClusterResources) {
                Write-Verbose "Processing cluster-scoped resources"
                foreach ($resource in $clusterScopedResources) {
                    $kubectlCmd = "get $resource -o json"
                    Write-Verbose "Running command: kubectl $kubectlCmd"
                    $resourceOutput = Invoke-KubectlCommand $kubectlCmd

                    if (-not $resourceOutput -or $resourceOutput -match '"items": \[\]') {
                        Write-Verbose "No $resource found. Skipping."
                        continue
                    }

                    $resourceOutputJson = $resourceOutput | ConvertFrom-Json
                    foreach ($item in $resourceOutputJson.items) {
                        $resourceName = $item.metadata.name
                        $kind = $item.kind
                        $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
                        $safeResourceName = $resourceName -replace "[:\\/]", "_"
                        $resourceFile = Join-Path -Path $OutputPath -ChildPath "${kind}_${safeResourceName}_$timestamp.yaml"
                        $item | ConvertTo-Yaml | Out-File -FilePath $resourceFile -Force
                        Write-Host "Saved $kind '$resourceName': $resourceFile" -ForegroundColor Green
                    }
                }
            }
        } catch {
            Write-Host "Error occurred while capturing snapshots: $_" -ForegroundColor Red
        }
    } else {
        Write-Host "Dry run: No snapshot was taken."
    }
}