Src/Private/Get-AbrIntuneE8Summary.ps1

function Get-AbrIntuneE8Summary {
    <#
    .SYNOPSIS
    Renders a consolidated ACSC Essential Eight Maturity Level assessment chapter.
    .DESCRIPTION
        Presents all accumulated E8 checks organised by the 8 pillars, matching the
        structure used in design documents (User Application Hardening, Office Macros,
        Patch Applications, Patch OS, Restrict Admin Privileges, Application Control,
        Phishing-Resistant MFA, and a rollup summary).

        This function is called AFTER all other sections have run so that
        $script:E8AllChecks is fully populated.
    .NOTES
        Version: 0.1.0
        Author: Pai Wei Sing
    #>

    [CmdletBinding()]
    param (
        [Parameter(Position = 0, Mandatory)]
        [string]$TenantId
    )

    begin {
        Write-PScriboMessage -Message "Rendering ACSC Essential Eight Summary for $TenantId."
        Show-AbrDebugExecutionTime -Start -TitleMessage 'E8 Summary'
    }

    process {
        if (-not $script:IncludeACSCe8) { return }
        if (-not $script:E8AllChecks -or $script:E8AllChecks.Count -eq 0) {
            Write-AbrDebugLog 'E8 Summary: no checks accumulated -- skipping chapter' 'WARN' 'E8SUMMARY'
            return
        }

        Section -Style Heading1 'ACSC Essential Eight Maturity Assessment' {
            Paragraph "This section provides a consolidated ACSC Essential Eight Maturity Level 1-3 assessment for tenant $TenantId, organised by the eight security control pillars. Controls are evaluated against the Intune configuration collected during this report run."
            BlankLine

            # ── Rollup summary table ───────────────────────────────────────────
            $AllChecks  = @($script:E8AllChecks)
            $TotalOK    = @($AllChecks | Where-Object { $_.Status -eq '[OK]' }).Count
            $TotalWarn  = @($AllChecks | Where-Object { $_.Status -eq '[WARN]' }).Count
            $TotalFail  = @($AllChecks | Where-Object { $_.Status -eq '[FAIL]' }).Count
            $TotalInfo  = @($AllChecks | Where-Object { $_.Status -eq '[INFO]' }).Count
            $TotalAll   = $AllChecks.Count

            $SummObj = [System.Collections.ArrayList]::new()
            $SummObj.Add([pscustomobject]@{ Result = '[OK]';   Count = $TotalOK;   Description = 'Controls meeting maturity requirements' }) | Out-Null
            $SummObj.Add([pscustomobject]@{ Result = '[WARN]'; Count = $TotalWarn; Description = 'Controls partially configured or recommended improvements' }) | Out-Null
            $SummObj.Add([pscustomobject]@{ Result = '[FAIL]'; Count = $TotalFail; Description = 'Controls not meeting maturity requirements' }) | Out-Null
            $SummObj.Add([pscustomobject]@{ Result = '[INFO]'; Count = $TotalInfo; Description = 'Informational checks (manual verification recommended)' }) | Out-Null
            $SummObj.Add([pscustomobject]@{ Result = 'Total';  Count = $TotalAll;  Description = 'All controls evaluated' }) | Out-Null

            $null = (& {
                if ($HealthCheck.Intune.DeviceCompliance -or $HealthCheck.Intune.EndpointSecurity) {
                    $null = ($SummObj | Where-Object { $_.Result -eq '[OK]'   } | Set-Style -Style OK       | Out-Null)
                    $null = ($SummObj | Where-Object { $_.Result -eq '[WARN]' } | Set-Style -Style Warning  | Out-Null)
                    $null = ($SummObj | Where-Object { $_.Result -eq '[FAIL]' } | Set-Style -Style Critical | Out-Null)
                }
            })

            $SummParams = @{ Name = "E8 Assessment Summary - $TenantId"; ColumnWidths = 12, 12, 76 }
            if ($Report.ShowTableCaptions) { $SummParams['Caption'] = "- $($SummParams.Name)" }
            $SummObj | Table @SummParams

            BlankLine

            # ── ML breakdown ───────────────────────────────────────────────────
            foreach ($ML in @('ML1', 'ML2', 'ML3')) {
                $mlChecks = @($AllChecks | Where-Object { $_.ML -eq $ML })
                if ($mlChecks.Count -eq 0) { continue }
                $mlOK   = @($mlChecks | Where-Object { $_.Status -eq '[OK]' }).Count
                $mlFail = @($mlChecks | Where-Object { $_.Status -eq '[FAIL]' }).Count
                $mlWarn = @($mlChecks | Where-Object { $_.Status -eq '[WARN]' }).Count
                $mlPct  = if ($mlChecks.Count -gt 0) { [int](($mlOK / $mlChecks.Count) * 100) } else { 0 }
                $mlLabel = switch ($ML) {
                    'ML1' { 'Maturity Level 1 — Partly Aligned' }
                    'ML2' { 'Maturity Level 2 — Mostly Aligned' }
                    'ML3' { 'Maturity Level 3 — Fully Aligned' }
                }
                BlankLine
                Paragraph "${mlLabel}: ${mlOK}/$($mlChecks.Count) controls passing (${mlPct}%) — ${mlFail} failing, ${mlWarn} warnings."
                BlankLine

                $null = (& {
                    if ($HealthCheck.Intune.DeviceCompliance -or $HealthCheck.Intune.EndpointSecurity) {
                        $null = ($mlChecks | Where-Object { $_.Status -eq '[FAIL]' } | Set-Style -Style Critical | Out-Null)
                        $null = ($mlChecks | Where-Object { $_.Status -eq '[WARN]' } | Set-Style -Style Warning  | Out-Null)
                        $null = ($mlChecks | Where-Object { $_.Status -eq '[OK]'   } | Set-Style -Style OK       | Out-Null)
                    }
                })

                $MLParams = @{ Name = "E8 $ML Controls - $TenantId"; ColumnWidths = 8, 32, 9, 51 }
                if ($Report.ShowTableCaptions) { $MLParams['Caption'] = "- $($MLParams.Name)" }
                ($mlChecks | Select-Object ML, Control, Status, Detail) | Table @MLParams
            }

            BlankLine

            # ── Pillar breakdown ───────────────────────────────────────────────
            # Map sections to ACSC E8 pillar names
            $PillarMap = [ordered]@{
                'User Application Hardening'       = @('ConfigurationProfiles')
                'Restrict Microsoft Office Macros' = @('AppManagement')
                'Patch Applications'               = @('DeviceCompliance', 'Devices')
                'Patch Operating Systems'          = @('DeviceCompliance', 'Devices')
                'Restrict Administrative Privileges' = @('Scripts', 'EndpointSecurity')
                'Application Control'              = @('EndpointSecurity')
                'Regular Backups'                  = @()
                'Multi-factor Authentication'      = @('EnrollmentRestrictions')
            }

            Paragraph "Assessment by Essential Eight Control Pillar:"
            BlankLine

            $PillarSummObj = [System.Collections.ArrayList]::new()
            foreach ($Pillar in $PillarMap.GetEnumerator()) {
                $pillarChecks = if ($Pillar.Value.Count -gt 0) {
                    @($AllChecks | Where-Object { $Pillar.Value -contains $_.Section })
                } else { @() }

                $pOK   = @($pillarChecks | Where-Object { $_.Status -eq '[OK]'   }).Count
                $pWarn = @($pillarChecks | Where-Object { $_.Status -eq '[WARN]' }).Count
                $pFail = @($pillarChecks | Where-Object { $_.Status -eq '[FAIL]' }).Count
                $pTotal = $pillarChecks.Count

                $pillarStatus = if ($pTotal -eq 0) {
                    '[INFO]'
                } elseif ($pFail -gt 0) {
                    '[FAIL]'
                } elseif ($pWarn -gt 0) {
                    '[WARN]'
                } else {
                    '[OK]'
                }

                $PillarSummObj.Add([pscustomobject]([ordered]@{
                    'Pillar'       = $Pillar.Key
                    'Status'       = $pillarStatus
                    'OK'           = $pOK
                    'Warn'         = $pWarn
                    'Fail'         = $pFail
                    'Total Checks' = $pTotal
                })) | Out-Null
            }

            $null = (& {
                if ($HealthCheck.Intune.DeviceCompliance -or $HealthCheck.Intune.EndpointSecurity) {
                    $null = ($PillarSummObj | Where-Object { $_.Status -eq '[OK]'   } | Set-Style -Style OK       | Out-Null)
                    $null = ($PillarSummObj | Where-Object { $_.Status -eq '[WARN]' } | Set-Style -Style Warning  | Out-Null)
                    $null = ($PillarSummObj | Where-Object { $_.Status -eq '[FAIL]' } | Set-Style -Style Critical | Out-Null)
                }
            })

            $PillarParams = @{ Name = "E8 Pillar Summary - $TenantId"; ColumnWidths = 36, 10, 9, 9, 9, 27 }
            if ($Report.ShowTableCaptions) { $PillarParams['Caption'] = "- $($PillarParams.Name)" }
            $PillarSummObj | Table @PillarParams

            BlankLine

            # ── Controls requiring attention ───────────────────────────────────
            $FailWarnChecks = @($AllChecks | Where-Object { $_.Status -in @('[FAIL]', '[WARN]') } | Sort-Object ML, Status)
            if ($FailWarnChecks.Count -gt 0) {
                BlankLine
                Paragraph "Controls Requiring Attention ($($FailWarnChecks.Count) item(s)):"
                BlankLine

                $null = (& {
                    if ($HealthCheck.Intune.DeviceCompliance -or $HealthCheck.Intune.EndpointSecurity) {
                        $null = ($FailWarnChecks | Where-Object { $_.Status -eq '[FAIL]' } | Set-Style -Style Critical | Out-Null)
                        $null = ($FailWarnChecks | Where-Object { $_.Status -eq '[WARN]' } | Set-Style -Style Warning  | Out-Null)
                    }
                })

                $AttnParams = @{ Name = "E8 Controls Requiring Attention - $TenantId"; ColumnWidths = 8, 32, 9, 51 }
                if ($Report.ShowTableCaptions) { $AttnParams['Caption'] = "- $($AttnParams.Name)" }
                ($FailWarnChecks | Select-Object ML, Control, Status, Detail) | Table @AttnParams
            }

            # ── Store in Excel ─────────────────────────────────────────────────
            if ((Get-IntuneExcelSheetEnabled -SheetKey 'ACSCe8Assessment') -and $AllChecks.Count -gt 0) {
                $script:ExcelSheets['ACSC E8 Assessment'] = $AllChecks
            }
        }
    }

    end { Show-AbrDebugExecutionTime -End -TitleMessage 'E8 Summary' }
}