Private/Save-KubeSnapshot.ps1

function Save-KubeSnapshot {
    param (
        [string]$Namespace,
        [switch]$AllNamespaces,
        [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     # kubectl command without the 'kubectl' part
        )
        $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

        # Start the kubectl process
        $process.Start() | Out-Null

        # Capture output and error
        $output = $process.StandardOutput.ReadToEnd()
        $stderr = $process.StandardError.ReadToEnd()
        $process.WaitForExit()

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

        return $output
    }

    # 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"
    )

    # Command to capture all pods if no specific pod is provided
    $unmanagedPodsCmd = "get pods --output=json"

    # Set namespace option based on parameters
    if ($AllNamespaces) {
        $namespaceOption = "--all-namespaces"
        $unmanagedPodsCmd += " --all-namespaces"
    }
    elseif ($AllNonSystemNamespaces) {
        # Get all non-system namespaces
        $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) {
        # Check if the namespace exists
        $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"
        $unmanagedPodsCmd += " -n $Namespace"
    }
    else {
        $namespaceOption = ""
    }

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

    if (-not $DryRun) {
        try {
            $resourcesFound = $false  # Flag to track if any resources are found

            # Function to process resources in a namespace
            function Process-Namespace {
                param (
                    [string]$Namespace
                )

                $namespaceOption = "-n $Namespace"
                $unmanagedPodsCmd = "get pods -n $Namespace --output=json"

                # If specific objects are provided, process them first
                if ($Objects) {
                    $ObjectsArray = $Objects -split ","

                    foreach ($object in $ObjectsArray) {
                        $kind, $name = $object.Trim() -split "/"
                        $kubectlCmd = "get $kind $name $namespaceOption -o yaml"
                        Write-Verbose "Running command: kubectl $kubectlCmd"
                        $resourceOutput = Invoke-KubectlCommand $kubectlCmd

                        if ($resourceOutput) {
                            $resourcesFound = $true  # Resources found
                            $resourceOutputYaml = $resourceOutput | ConvertFrom-Yaml
                            $resourceName = $resourceOutputYaml.metadata.name
                            $kind = $resourceOutputYaml.kind
                            $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"

                            # Sanitize the resourceName by replacing invalid characters with underscores
                            $safeResourceName = $resourceName -replace "[:\\/]", "_"

                            # Generate a filename based on the kind and name of the resource
                            $resourceFile = Join-Path -Path $OutputPath -ChildPath "${kind}_${safeResourceName}_$timestamp.yaml"

                            Write-Verbose "Saving $kind '$resourceName' snapshot to: $resourceFile"
                            $resourceOutput | Out-File -FilePath $resourceFile -Force
                            Write-Host "$kind '$resourceName' snapshot saved: $resourceFile" -ForegroundColor Green
                        }
                    }
                }
                else {
                    # Capture namespaced resources
                    foreach ($resource in $namespacedResources) {
                        $kubectlCmd = "get $resource $namespaceOption $labelOption -o json"
                        Write-Verbose "Running command: kubectl $kubectlCmd"
                        $resourceOutput = Invoke-KubectlCommand $kubectlCmd

                        # Skip if the resource does not exist (i.e., no items)
                        if (-not $resourceOutput -or $resourceOutput -eq "null" -or $resourceOutput.Contains('"items": []')) {
                            Write-Verbose "No $resource found in this namespace. Skipping."
                            continue
                        }

                        $resourcesFound = $true  # Resources found

                        # Convert JSON to objects for easier processing
                        $resourceOutputJson = $resourceOutput | ConvertFrom-Json

                        # Process each individual item in the resource output
                        foreach ($item in $resourceOutputJson.items) {
                            $resourceName = $item.metadata.name
                            $kind = $item.kind
                            $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"

                            # Sanitize the resourceName by replacing invalid characters with underscores
                            $safeResourceName = $resourceName -replace "[:\\/]", "_"

                            # Generate a filename based on the kind and name of the resource
                            $resourceFile = Join-Path -Path $OutputPath -ChildPath "${kind}_${safeResourceName}_$timestamp.yaml"

                            # Convert the item back to YAML and save it
                            $item | ConvertTo-Yaml | Out-File -FilePath $resourceFile -Force
                            Write-Verbose "Saving $kind '$resourceName' snapshot to: $resourceFile"
                            Write-Host "$kind '$resourceName' snapshot saved: $resourceFile" -ForegroundColor Green
                        }
                    }

                    # Capture unmanaged pods (those without ownerReferences)
                    Write-Verbose "Running command for unmanaged pods: $unmanagedPodsCmd"
                    $unmanagedPodsOutput = Invoke-KubectlCommand $unmanagedPodsCmd
                    if ($unmanagedPodsOutput) {
                        $resourcesFound = $true  # Resources found
                        $unmanagedPodsOutputJson = $unmanagedPodsOutput | ConvertFrom-Json
                        foreach ($pod in $unmanagedPodsOutputJson.items) {
                            if (-not $pod.metadata.ownerReferences) {
                                $podName = $pod.metadata.name
                                $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
                                $unmanagedPodFile = Join-Path -Path $OutputPath -ChildPath "unmanaged_pod_${podName}_$timestamp.yaml"

                                $pod | ConvertTo-Yaml | Out-File -FilePath $unmanagedPodFile -Force
                                Write-Verbose "Saving unmanaged pod '$podName' snapshot to: $unmanagedPodFile"
                                Write-Host "Unmanaged pod '$podName' snapshot saved: $unmanagedPodFile" -ForegroundColor Green
                            }
                        }
                    }
                }
            }

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

            # Capture cluster-scoped resources if AllNamespaces is specified
            if ($AllNamespaces) {
                $clusterResourcesFound = $false  # Track if any cluster-scoped resources are found

                foreach ($resource in $clusterScopedResources) {
                    $kubectlCmd = "get $resource -o json" # No namespace option for cluster-scoped resources
                    Write-Verbose "Running command: kubectl $kubectlCmd"
                    $resourceOutput = Invoke-KubectlCommand $kubectlCmd

                    # Skip if the resource does not exist (i.e., no items)
                    if (-not $resourceOutput -or $resourceOutput -eq "null" -or $resourceOutput.Contains('"items": []')) {
                        Write-Verbose "No $resource found. Skipping."
                        continue
                    }

                    $clusterResourcesFound = $true  # Resources found

                    # Convert JSON to objects for easier processing
                    $resourceOutputJson = $resourceOutput | ConvertFrom-Json

                    # Process each individual item in the resource output
                    foreach ($item in $resourceOutputJson.items) {
                        $resourceName = $item.metadata.name
                        $kind = $item.kind
                        $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"

                        # Sanitize the resourceName by replacing invalid characters with underscores
                        $safeResourceName = $resourceName -replace "[:\\/]", "_"

                        # Generate a filename based on the kind and name of the resource
                        $resourceFile = Join-Path -Path $OutputPath -ChildPath "${kind}_${safeResourceName}_$timestamp.yaml"

                        # Convert the item back to YAML and save it
                        $item | ConvertTo-Yaml | Out-File -FilePath $resourceFile -Force
                        Write-Verbose "Saving $kind '$resourceName' snapshot to: $resourceFile"
                        Write-Host "$kind '$resourceName' snapshot saved: $resourceFile" -ForegroundColor Green
                    }
                }

                # If no cluster-scoped resources were found
                if (-not $clusterResourcesFound) {
                    Write-Host "No cluster-scoped resources found." -ForegroundColor Yellow
                }
            }

            # If no resources were found in the namespace
            if (-not $resourcesFound) {
                Write-Host "No resources found in the namespace '$Namespace'." -ForegroundColor Yellow
            }

        }
        catch {
            Write-Host "Error occurred while capturing the snapshot: $_" -ForegroundColor Red
        }
    }
    else {
        Write-Host "Dry run: No snapshot was taken."
    }
}