Reports/New-CISJsonReport.ps1
|
function New-CISJsonReport { [CmdletBinding()] param( [Parameter(Mandatory)] [PSCustomObject[]]$Results, [Parameter(Mandatory)] [string]$OutputPath, [Parameter()] [hashtable]$Metadata = @{} ) # Single-pass counting instead of multiple Where-Object calls $total = $Results.Count $pass = 0 $fail = 0 $warning = 0 $info = 0 $error_ = 0 foreach ($r in $Results) { switch ($r.Status) { 'PASS' { $pass++ } 'FAIL' { $fail++ } 'WARNING' { $warning++ } 'INFO' { $info++ } 'ERROR' { $error_++ } } } # Exclude INFO, WARNING, and ERROR from the scoring denominator $scoreDenom = $total - $info - $warning - $error_ $overallScore = if ($scoreDenom -gt 0) { [math]::Round(($pass / $scoreDenom) * 100, 1) } else { -1 } $report = [ordered]@{ benchmarkVersion = "CIS Microsoft Azure Foundations Benchmark $(if ($script:CISBenchmarkVersion) { $script:CISBenchmarkVersion } else { 'v5.0.0' })" scanTimestamp = if ($Metadata.ScanTimestamp) { $Metadata.ScanTimestamp } else { [DateTime]::UtcNow.ToString('o') } subscriptionName = if ($Metadata.SubscriptionName) { $Metadata.SubscriptionName } else { 'N/A' } subscriptionId = if ($Metadata.SubscriptionId) { $Metadata.SubscriptionId } else { 'N/A' } tenantId = if ($Metadata.TenantId) { $Metadata.TenantId } else { 'N/A' } summary = [ordered]@{ overallScore = $overallScore totalControls = $total passed = $pass failed = $fail warning = $warning info = $info error = $error_ } sectionBreakdown = ($Results | Group-Object Section | ForEach-Object { $sTotal = $_.Group.Count $sPass = 0; $sFail = 0; $sWarn = 0; $sInfo = 0; $sError = 0 foreach ($item in $_.Group) { switch ($item.Status) { 'PASS' { $sPass++ } 'FAIL' { $sFail++ } 'WARNING' { $sWarn++ } 'INFO' { $sInfo++ } 'ERROR' { $sError++ } } } $sDenom = $sTotal - $sInfo - $sWarn - $sError [ordered]@{ section = $_.Name total = $sTotal passed = $sPass failed = $sFail warning = $sWarn info = $sInfo error = $sError score = if ($sDenom -gt 0) { [math]::Round(($sPass / $sDenom) * 100, 1) } else { -1 } } }) results = ($Results | ForEach-Object { [ordered]@{ controlId = $_.ControlId title = $_.Title status = $_.Status severity = $_.Severity section = $_.Section subsection = $_.Subsection assessmentStatus = $_.AssessmentStatus profileLevel = $_.ProfileLevel description = $_.Description details = $_.Details remediation = $_.Remediation affectedResources = $_.AffectedResources totalResources = $_.TotalResources passedResources = $_.PassedResources failedResources = $_.FailedResources references = $_.References cisControls = $_.CISControls timestamp = $_.Timestamp } }) } $report | ConvertTo-Json -Depth 10 | Out-File -FilePath $OutputPath -Encoding UTF8 -Force Write-Verbose "JSON report written to: $OutputPath" return $OutputPath } |