Private/Create-CsvReport.ps1
|
function Create-CsvReport { param ( [string]$OutputPath, [object]$KubeData, [switch]$ExcludeNamespaces, [switch]$Aks, [string]$SubscriptionId, [string]$ResourceGroup, [string]$ClusterName ) # Strip all newlines and extra whitespace from a string value filter Format-CsvValue { ([string]$_) -replace '[\r\n]+', ' ' -replace '[^\x00-\x7F\u00C0-\u024F]', '' -replace '\s{2,}', ' ' | ForEach-Object { $_.Trim() } } # Run YAML-based checks $yamlCheckResults = Invoke-yamlChecks -Json -KubeData $KubeData -ExcludeNamespaces:$ExcludeNamespaces $rows = [System.Collections.Generic.List[PSCustomObject]]::new() foreach ($check in $yamlCheckResults.Items) { if (-not $check.ID) { continue } $status = if ($check.Error) { "ERROR" } elseif ($check.Total -gt 0) { "FAIL" } else { "PASS" } $recommendation = if ($check.Recommendation -is [hashtable] -or $check.Recommendation -is [System.Collections.Hashtable]) { $check.Recommendation.text | Format-CsvValue } else { $check.Recommendation | Format-CsvValue } $checkId = $check.ID | Format-CsvValue $checkName = $check.Name | Format-CsvValue $checkCategory = $check.Category | Format-CsvValue $checkSeverity = $check.Severity | Format-CsvValue $checkUrl = $check.URL | Format-CsvValue if ($status -eq "FAIL" -and $check.Items -and $check.Items.Count -gt 0) { foreach ($item in $check.Items) { $parts = @() if ($item.Namespace) { $parts += $item.Namespace | Format-CsvValue } if ($item.Resource) { $parts += $item.Resource | Format-CsvValue } if ($item.Message) { $parts += $item.Message | Format-CsvValue } elseif ($item.Issue) { $parts += $item.Issue | Format-CsvValue } $rows.Add([PSCustomObject]@{ ID = $checkId Name = $checkName Category = $checkCategory Severity = $checkSeverity Status = $status Message = $parts -join " | " Recommendation = $recommendation URL = $checkUrl }) } } else { $message = if ($check.Message) { $check.Message | Format-CsvValue } elseif ($check.SummaryMessage) { $check.SummaryMessage | Format-CsvValue } elseif ($check.Error) { $check.Error | Format-CsvValue } else { "" } $rows.Add([PSCustomObject]@{ ID = $checkId Name = $checkName Category = $checkCategory Severity = $checkSeverity Status = $status Message = $message Recommendation = $recommendation URL = $checkUrl }) } } # AKS-specific checks if ($Aks) { try { $aksCheckResults = Invoke-AKSBestPractices -Json -KubeData $KubeData -SubscriptionId $SubscriptionId -ResourceGroup $ResourceGroup -ClusterName $ClusterName if ($aksCheckResults -and $aksCheckResults.Items) { foreach ($check in $aksCheckResults.Items) { if (-not $check.ID) { continue } $rawStatus = [string]$check.Status $status = if ($rawStatus -match "PASS") { "PASS" } elseif ($rawStatus -match "ERROR") { "ERROR" } elseif ($rawStatus -match "FAIL") { "FAIL" } else { $rawStatus } $message = if ($check.FailMessage) { $check.FailMessage | Format-CsvValue } else { $check.ObservedValue | Format-CsvValue } $recommendation = if ($check.Recommendation -is [hashtable] -or $check.Recommendation -is [System.Collections.Hashtable]) { $check.Recommendation.text | Format-CsvValue } else { $check.Recommendation | Format-CsvValue } $rows.Add([PSCustomObject]@{ ID = $check.ID | Format-CsvValue Name = $check.Name | Format-CsvValue Category = $check.Category | Format-CsvValue Severity = $check.Severity | Format-CsvValue Status = $status Message = $message Recommendation = $recommendation URL = $check.URL | Format-CsvValue }) } } } catch { Write-Warning "Failed to run AKS best practices for CSV report: $_" } } $csv = $rows | ConvertTo-Csv -NoTypeInformation [System.IO.File]::WriteAllLines($OutputPath, $csv, [System.Text.UTF8Encoding]::new($true)) } |