Private/Export-sqmWhoIsActiveReport.ps1

<#
.SYNOPSIS
    Schreibt CSV (alle Snapshots) und HTML (nur letzter Snapshot) fuer einen WhoIsActive-Lauf.
 
.DESCRIPTION
    Gemeinsame Report-Erzeugung fuer Get-sqmWhoIsActive und Show-sqmWhoIsActiveMonitor:
    die CSV enthaelt die komplette Historie aller Iterationen eines Laufs (fuer
    Nachanalyse), der HTML-Bericht bewusst NUR den letzten Snapshot - bei einem
    Dauerlauf ueber ggf. hunderte Iterationen ist der aktuelle Zustand relevant,
    nicht ein sich staendig verlaengernder Verlauf.
 
.PARAMETER AllSnapshots
    Alle Zeilen aus allen Iterationen des Laufs (-> CSV).
 
.PARAMETER LastSnapshotRows
    Nur die Zeilen der letzten Iteration (-> HTML).
 
.PARAMETER IterationCount
    Anzahl der insgesamt durchgefuehrten Iterationen (fuer die HTML-Kopfzeile).
 
.NOTES
    Privat - wird ausschliesslich von Get-sqmWhoIsActive und Show-sqmWhoIsActiveMonitor
    aufgerufen. Schreibt nichts und liefert leere Pfade, wenn AllSnapshots leer ist.
#>

function Export-sqmWhoIsActiveReport
{
    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param (
        [Parameter(Mandatory = $true)]
        [AllowEmptyCollection()]
        [object[]]$AllSnapshots,
        [Parameter(Mandatory = $true)]
        [AllowEmptyCollection()]
        [object[]]$LastSnapshotRows,
        [Parameter(Mandatory = $true)]
        [string]$SqlInstance,
        [Parameter(Mandatory = $true)]
        [string]$OutputPath,
        [Parameter(Mandatory = $true)]
        [int]$IterationCount,
        [Parameter(Mandatory = $true)]
        [datetime]$LoopStart,
        [Parameter(Mandatory = $false)]
        [switch]$NoOpen
    )

    $result = [PSCustomObject]@{ CsvFile = $null; HtmlFile = $null }
    if (-not $OutputPath -or $AllSnapshots.Count -eq 0) { return $result }

    if (-not (Test-Path $OutputPath))
    {
        New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null
    }
    $stamp = Get-Date -Format 'yyyyMMdd_HHmmss'
    $safeInst = $SqlInstance -replace '\\', '_'

    $csvFile = Join-Path $OutputPath "WhoIsActive_${safeInst}_${stamp}.csv"
    $AllSnapshots | Export-Csv -Path $csvFile -NoTypeInformation -Encoding UTF8 -Force

    $htmlFile = Join-Path $OutputPath "WhoIsActive_${safeInst}_${stamp}.html"
    $rowsHtml = foreach ($s in $LastSnapshotRows)
    {
        $elapsedTxt = Format-sqmTimeSpan -Seconds ([math]::Max(0, [int]$s.ElapsedSeconds))
        $sevClass = if ($s.BlockingSessionId -gt 0) { 'crit' } elseif ($s.ElapsedSeconds -ge 30) { 'warn' } else { 'ok' }
        "<tr><td class='$sevClass'>$($s.SessionId)</td><td>$elapsedTxt</td><td>$([System.Net.WebUtility]::HtmlEncode([string]$s.Status))</td><td>$($s.BlockingSessionId)</td><td>$([System.Net.WebUtility]::HtmlEncode([string]$s.WaitInfo))</td><td>$([System.Net.WebUtility]::HtmlEncode([string]$s.DatabaseName))</td><td>$([System.Net.WebUtility]::HtmlEncode([string]$s.LoginName))</td><td>$([System.Net.WebUtility]::HtmlEncode([string]$s.HostName))</td><td>$($s.CpuTimeMs)</td><td>$($s.Reads)</td><td>$($s.TempdbAllocMB)</td><td>$([System.Net.WebUtility]::HtmlEncode([string]$s.SqlText))</td></tr>"
    }
    $bodyHtml = "<p>$IterationCount Snapshot(s) erfasst zwischen $($LoopStart.ToString('yyyy-MM-dd HH:mm:ss')) und $((Get-Date).ToString('yyyy-MM-dd HH:mm:ss')). Letzter Snapshot: $($LastSnapshotRows.Count) Session(s).</p>" +
        "<table><tr><th>SPID</th><th>Elapsed</th><th>Status</th><th>Blocked by</th><th>Wait Info</th><th>Datenbank</th><th>Login</th><th>Host</th><th>CPU ms</th><th>Reads</th><th>Tempdb MB</th><th>SQL Text</th></tr>" +
        ($rowsHtml -join '') + "</table>"
    $html = ConvertTo-sqmHtmlReport -Title "Who Is Active - $SqlInstance" -Subtitle "Letzter Snapshot: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') ($IterationCount Snapshot(s) gesamt)" -BodyHtml $bodyHtml
    $html | Out-File -FilePath $htmlFile -Encoding UTF8 -Force

    Invoke-sqmOpenReport -HtmlFile $htmlFile -NoOpen:$NoOpen

    $result.CsvFile = $csvFile
    $result.HtmlFile = $htmlFile
    return $result
}