Functions/Public/Show-StopwatchSummary.ps1
|
function Show-StopwatchSummary { <# .SYNOPSIS Displays a formatted summary of all stopwatch timings. .DESCRIPTION Prints a nicely formatted table of all completed stopwatch results, sorted by duration (longest first). Useful for performance analysis and identifying bottlenecks. .PARAMETER Name Optional. Filter to show only stopwatches matching this pattern. Supports wildcards. .PARAMETER SortBy How to sort the results: - Duration (default): Longest to shortest - Name: Alphabetical order - StartTime: Chronological order .PARAMETER Descending Sort in descending order (default for Duration). .PARAMETER Ascending Sort in ascending order. .PARAMETER IncludeRunning Also shows currently running stopwatches (not yet stopped). .PARAMETER Title Custom title for the summary header. Default: "Performance Summary" .PARAMETER NoHeader Suppresses the header/title display. .OUTPUTS None. Writes formatted output to the host. .EXAMPLE Show-StopwatchSummary # Shows all completed stopwatch timings .EXAMPLE Show-StopwatchSummary -Name "API*" -Title "API Performance" # Shows only API-related timings with custom title .EXAMPLE Show-StopwatchSummary -IncludeRunning # Also shows stopwatches that haven't been stopped yet .EXAMPLE Show-StopwatchSummary -SortBy Name -Ascending # Shows results sorted alphabetically .NOTES Author: Sune Alexandersen Narud Version: 1.0.0 Date: February 2026 .LINK Start-Stopwatch Stop-Stopwatch Get-Stopwatch Reset-Stopwatch #> [CmdletBinding()] [OutputType([void])] param( [Parameter(Position = 0)] [SupportsWildcards()] [string]$Name = '*', [Parameter()] [ValidateSet('Duration', 'Name', 'StartTime')] [string]$SortBy = 'Duration', [Parameter()] [switch]$Descending, [Parameter()] [switch]$Ascending, [Parameter()] [switch]$IncludeRunning, [Parameter()] [string]$Title = 'Performance Summary', [Parameter()] [switch]$NoHeader ) # Collect results $results = @() # Get completed stopwatches if ($Global:OrionStopwatchResults) { foreach ($key in $Global:OrionStopwatchResults.Keys) { if ($key -like $Name) { $result = $Global:OrionStopwatchResults[$key] $results += [PSCustomObject]@{ Name = $result.Name Status = 'Completed' StartTime = $result.StartTime Duration = $result.Duration TotalSeconds = $result.TotalSeconds } } } } # Optionally include running stopwatches if ($IncludeRunning -and $Global:OrionStopwatches) { $now = [DateTime]::Now foreach ($key in $Global:OrionStopwatches.Keys) { if ($key -like $Name) { $startTime = $Global:OrionStopwatches[$key] $elapsed = $now - $startTime $results += [PSCustomObject]@{ Name = $key Status = 'Running' StartTime = $startTime Duration = $elapsed TotalSeconds = $elapsed.TotalSeconds } } } } # Check if we have any results if ($results.Count -eq 0) { Write-Host "" Write-Host " No stopwatch data available." -ForegroundColor Yellow Write-Host " Use Start-Stopwatch and Stop-Stopwatch to record timings." -ForegroundColor DarkGray Write-Host "" return } # Determine sort order $sortDescending = switch ($SortBy) { 'Duration' { -not $Ascending } # Default descending for duration 'Name' { $Descending } # Default ascending for name 'StartTime' { $Descending } # Default ascending for time } # Sort results $sortProperty = switch ($SortBy) { 'Duration' { 'TotalSeconds' } 'Name' { 'Name' } 'StartTime' { 'StartTime' } } $results = $results | Sort-Object -Property $sortProperty -Descending:$sortDescending # Calculate column widths $maxNameLength = ($results.Name | Measure-Object -Property Length -Maximum).Maximum $maxNameLength = [Math]::Max($maxNameLength, 4) # Minimum width for "Name" header $timeWidth = 15 # Fixed width for time column $boxWidth = $maxNameLength + $timeWidth + 6 # 6 = "· " + " " spacing # Display header if (-not $NoHeader) { Write-Host "" $headerLine = "═" * $boxWidth Write-Host " ╔$headerLine╗" -ForegroundColor DarkCyan $paddedTitle = " $Title ".PadRight($boxWidth) Write-Host " ║" -ForegroundColor DarkCyan -NoNewline Write-Host "$paddedTitle" -ForegroundColor Cyan -NoNewline Write-Host "║" -ForegroundColor DarkCyan Write-Host " ╠$headerLine╣" -ForegroundColor DarkCyan } # Calculate total time $totalSeconds = ($results | Measure-Object -Property TotalSeconds -Sum).Sum # Display each row foreach ($item in $results) { $paddedName = $item.Name.PadRight($maxNameLength) # Format the duration $formattedTime = if (Get-Command -Name 'Format-TimeSpan' -ErrorAction SilentlyContinue) { Format-TimeSpan -TimeSpan $item.Duration } else { $ts = $item.TotalSeconds if ($ts -lt 60) { "$([math]::Round($ts, 1)) sec" } else { $m = [int]($ts / 60) $s = [int]($ts % 60) "$m min $s sec" } } $formattedTime = $formattedTime.PadLeft($timeWidth) # Status indicator and row content Write-Host " ║ " -ForegroundColor DarkCyan -NoNewline if ($item.Status -eq 'Running') { Write-Host "» " -ForegroundColor Yellow -NoNewline } else { Write-Host "· " -ForegroundColor Green -NoNewline } Write-Host "$paddedName" -ForegroundColor White -NoNewline Write-Host " $formattedTime" -ForegroundColor Yellow -NoNewline Write-Host " ║" -ForegroundColor DarkCyan } # Display footer with total if (-not $NoHeader) { $footerLine = "─" * $boxWidth Write-Host " ╠$footerLine╣" -ForegroundColor DarkCyan $totalFormatted = if (Get-Command -Name 'Format-TimeSpan' -ErrorAction SilentlyContinue) { Format-TimeSpan -TimeSpan ([TimeSpan]::FromSeconds($totalSeconds)) } else { if ($totalSeconds -lt 60) { "$([math]::Round($totalSeconds, 1)) sec" } else { $m = [int]($totalSeconds / 60) $s = [int]($totalSeconds % 60) "$m min $s sec" } } $totalLabel = " TOTAL".PadRight($maxNameLength + 2) $totalFormatted = $totalFormatted.PadLeft($timeWidth) Write-Host " ║ " -ForegroundColor DarkCyan -NoNewline Write-Host "$totalLabel" -ForegroundColor Cyan -NoNewline Write-Host " $totalFormatted" -ForegroundColor Magenta -NoNewline Write-Host " ║" -ForegroundColor DarkCyan $closeLine = "═" * $boxWidth Write-Host " ╚$closeLine╝" -ForegroundColor DarkCyan Write-Host "" } } |