Private/Show-AACDiagnosticSettingView.ps1

function Show-AACDiagnosticSettingView {
    <#
    .SYNOPSIS
        Renders Get-AACDiagnosticSetting's result as a Spectre.Console view.
    .DESCRIPTION
        The scope, tiles, then:
          Coverage by resource type least covered first
          Workspaces receiving logs found or not, expected or not
          Misconfigurations each finding, with how many resources
                                      and which (up to -MaxRow)
          Not exported the resources whose logs don't all
                                      reach a workspace (up to -MaxRow)
        Wrap the call in Invoke-AACPagedOutput to page it.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [hashtable] $Diagnostic,

        [int] $MaxRow = 50
    )

    $escape = { param($Text) [Spectre.Console.Markup]::Escape([string]$Text) }
    $glyph = Get-AACGlyph
    $stats = $Diagnostic.Stats
    $severityColor = @{ High = 'red1'; Medium = 'orange1'; Low = 'deepskyblue1' }
    $statusColor = @{ Exported = 'green3'; Partial = 'orange1'; 'Not to workspace' = 'red1'; 'No setting' = 'red1'; Unknown = 'grey58'; 'No logs' = 'grey50' }
    $rateColor = { param($Rate) if ($null -eq $Rate) { 'grey50' } elseif ($Rate -ge 90) { 'green3' } elseif ($Rate -ge 60) { 'orange1' } else { 'red1' } }
    $count = { param([int] $Value, [string] $Color) if ($Value -eq 0) { '[grey42]0[/]' } else { "[$Color]$('{0:N0}' -f $Value)[/]" } }
    $newTable = {
        param([string] $Title, [string] $Color, [object[]] $Columns)
        $table = [Spectre.Console.Table]::new()
        $table.Border = [Spectre.Console.TableBorder]::Rounded
        $table.BorderStyle = [Spectre.Console.Style]::Parse($Color)
        $table.Expand = $true
        $table.Title = [Spectre.Console.TableTitle]::new($Title)
        foreach ($column in $Columns) {
            $spectre = [Spectre.Console.TableColumn]::new("[grey62]$($column[0])[/]")
            if ($column[1]) { $spectre.Alignment = [Spectre.Console.Justify]::Right; $spectre.NoWrap = $true }
            $table.AddColumn($spectre) | Out-Null
        }
        $table
    }
    $addRow = { param($Table, [string[]] $Cells) [Spectre.Console.TableExtensions]::AddRow($Table, [Spectre.Console.Rendering.IRenderable[]]@($Cells | ForEach-Object { [Spectre.Console.Markup]::new($_) })) | Out-Null }
    $write = { param($Table) [Spectre.Console.AnsiConsole]::Write($Table); [Spectre.Console.AnsiConsole]::WriteLine() }

    $facts = [System.Collections.Generic.List[string]]::new()
    if ($script:AACSession) { $facts.Add("[white]$(& $escape $script:AACSession.Account)[/]") }
    if ($Diagnostic.Scope) { foreach ($key in $Diagnostic.Scope.Keys) { $facts.Add("$(& $escape $key): $(& $escape $Diagnostic.Scope[$key])") } }
    $facts.Add((Get-Date).ToString('d MMM yyyy HH:mm'))
    Write-AACMarkup "[grey58]$($facts -join " $($glyph.Dot) ")[/]"
    [Spectre.Console.AnsiConsole]::WriteLine()
    Show-AACTileRow -Tile @(
        @{ Value = $(if ($null -ne $stats.CoveragePercent) { "$($stats.CoveragePercent)%" } else { '-' }); Caption = ('exported to Log Analytics ({0:N0} of {1:N0})' -f $stats.Exported, ($stats.WithLogs - $stats.Unknown)); Color = (& $rateColor $stats.CoveragePercent) }
        @{ Value = '{0:N0}' -f $stats.Partial; Caption = 'partly exported'; Color = 'orange1' }
        @{ Value = '{0:N0}' -f $stats.NotToWorkspace; Caption = 'settings, no workspace'; Color = 'red1' }
        @{ Value = '{0:N0}' -f $stats.NoSetting; Caption = 'no diagnostic setting'; Color = 'red1' }
        @{ Value = '{0:N0}' -f $stats.Settings; Caption = 'diagnostic settings'; Color = 'grey85' }
        @{ Value = '{0:N0}' -f $stats.Workspaces; Caption = 'workspaces receiving logs'; Color = 'mediumpurple2' }
        @{ Value = "$($stats.High) / $($stats.Medium) / $($stats.Low)"; Caption = 'findings H / M / L'; Color = $(if ($stats.High) { 'red1' } elseif ($stats.Medium) { 'orange1' } else { 'green3' }) }
    )
    [Spectre.Console.AnsiConsole]::WriteLine()
    foreach ($notice in @($Diagnostic.Notice | Where-Object { $_ })) { Write-AACMarkup "[deepskyblue1]i[/] [grey70]$(& $escape $notice)[/]" }
    if (@($Diagnostic.Notice).Count) { [Spectre.Console.AnsiConsole]::WriteLine() }
    if (-not $stats.WithLogs) { return }

    # --- Coverage by resource type -------------------------------------------------------------------------
    $table = & $newTable "[bold]$($glyph.Bullet) Coverage by resource type[/] [grey58]$($glyph.Dot) least covered first[/]" 'grey42' @(@('Resource type', $false), @('Coverage', $true), @('Exported', $true), @('Partial', $true), @('No workspace', $true), @('No setting', $true), @('Resources', $true))
    foreach ($row in $Diagnostic.ByType) {
        & $addRow $table @(
            "[bold]$(& $escape $row.ResourceType)[/]"
            $(if ($null -ne $row.CoveragePercent) { "[bold $(& $rateColor $row.CoveragePercent)]$($row.CoveragePercent)%[/]" } else { '[grey50]-[/]' })
            (& $count $row.Exported 'green3'); (& $count $row.Partial 'orange1'); (& $count $row.NotToWorkspace 'red1'); (& $count $row.NoSetting 'red1'); (& $count $row.Resources 'grey85')
        )
    }
    & $write $table

    # --- Workspaces --------------------------------------------------------------------------------------------
    if (@($Diagnostic.Workspaces).Count) {
        $table = & $newTable "[bold mediumpurple2]$($glyph.Bullet) Workspaces receiving logs[/]" 'mediumpurple2' @(@('Workspace', $false), @('Location', $false), @('Resources', $true), @('Settings', $true), @('', $false))
        foreach ($row in $Diagnostic.Workspaces) {
            $note = if (-not $row.Found) { '[red1]not found: deleted, or not visible to you[/]' } elseif ($false -eq $row.Expected) { '[orange1]not an expected workspace[/]' } elseif ($true -eq $row.Expected) { '[green3]expected[/]' } else { '' }
            & $addRow $table @("[bold]$(& $escape $row.Workspace)[/]", "[grey70]$(& $escape $row.Location)[/]", "$($row.Resources)", "$($row.Settings)", $note)
        }
        & $write $table
    }

    # --- Misconfigurations ----------------------------------------------------------------------------------------
    $rank = @{ High = 0; Medium = 1; Low = 2 }
    $groups = @($Diagnostic.Findings | Group-Object Severity, Finding | Sort-Object { $rank[$_.Group[0].Severity] }, { $_.Group[0].Finding })
    if ($groups.Count) {
        $table = & $newTable "[bold]$($glyph.Bullet) Misconfigurations[/] [grey58]$($glyph.Dot) $(@($Diagnostic.Findings).Count) finding(s)[/]" 'grey42' @(@('Severity', $false), @('Finding', $false), @('Resources', $true), @('Which', $false))
        foreach ($group in $groups) {
            $first = $group.Group[0]
            $names = @($group.Group | ForEach-Object Resource | Select-Object -Unique)
            $shown = @($names | Select-AACFirst 8)
            $which = ($shown | ForEach-Object { & $escape $_ }) -join ', '
            if ($names.Count -gt $shown.Count) { $which += " [grey50]+$($names.Count - $shown.Count) more[/]" }
            & $addRow $table @("[bold $($severityColor[$first.Severity])]$($first.Severity)[/]", "[bold]$(& $escape $first.Finding)[/]`n[grey58]$(& $escape $first.Action)[/]", "$($names.Count)", $which)
        }
        & $write $table
    }

    # --- Not exported ------------------------------------------------------------------------------------------
    $missing = @($Diagnostic.Shown | Where-Object Status -In 'No setting', 'Not to workspace', 'Partial')
    if ($missing.Count) {
        $table = & $newTable "[bold red1]$($glyph.Bullet) Logs not (all) reaching Log Analytics[/] [grey58]$($glyph.Dot) $($missing.Count) resource(s)[/]" 'red3' @(@('Resource', $false), @('Status', $false), @('What''s missing', $false))
        foreach ($row in $missing | Select-AACFirst $MaxRow) {
            $where = (@($row.ResourceGroup, $row.SubscriptionName) | Where-Object { $_ }) -join ' / '
            & $addRow $table @("[bold]$(& $escape $row.Resource)[/]`n[grey50]$(& $escape $row.ResourceType) $($glyph.Dot) $(& $escape $where)[/]", "[$($statusColor[$row.Status])]$(& $escape $row.Status)[/]", "[grey70]$(& $escape $row.Reason)[/]")
        }
        & $write $table
        if ($missing.Count -gt $MaxRow) { Write-AACMarkup "[grey50]... and $($missing.Count - $MaxRow) more: -PassThru, -CsvPath, -HtmlPath or -PdfPath lists them all.[/]"; [Spectre.Console.AnsiConsole]::WriteLine() }
    }
    elseif ($stats.WithLogs -and -not $stats.Unknown) {
        Show-AACPanel -Content '[bold green3]Every resource''s logs reach Log Analytics.[/]' -BorderColor 'green3' -AllowMarkup
        [Spectre.Console.AnsiConsole]::WriteLine()
    }
    Write-AACMarkup '[grey42]Add -PassThru (or pipe the command) for one row per resource, -ExpandSetting for one per diagnostic setting; -CsvPath, -PdfPath or -HtmlPath for a report.[/]'
}