Functions/Public/Stop-Stopwatch.ps1
|
function Stop-Stopwatch { <# .SYNOPSIS Stops a named stopwatch and records the elapsed time. .DESCRIPTION Calculates the elapsed time since Start-Stopwatch was called with the same name. Stores the duration in a global results dictionary for later retrieval or summary. Optionally displays the elapsed time. .PARAMETER Name The same identifier used with Start-Stopwatch. .PARAMETER ShowElapsed Displays the stopwatch name and elapsed time when stopping. Can be controlled globally via $Global:ShowStopwatchEnd. .PARAMETER Quiet Suppresses all output, overriding both -ShowElapsed and global settings. .PARAMETER PassThru Returns a PSCustomObject with Name, Duration (TimeSpan), and TotalSeconds. .OUTPUTS None by default. PSCustomObject if -PassThru is specified. .EXAMPLE Start-Stopwatch -Name "Data Import" Import-Csv "data.csv" | Process-Data Stop-Stopwatch -Name "Data Import" -ShowElapsed # Output: Data Import completed in 2 min 34 sec .EXAMPLE $result = Stop-Stopwatch -Name "API Call" -PassThru Write-Host "API took $($result.TotalSeconds) seconds" .EXAMPLE $Global:ShowStopwatchEnd = $true Stop-Stopwatch -Name "Build" # Automatically shows elapsed time .NOTES Author: Sune Alexandersen Narud Version: 1.0.0 Date: February 2026 .LINK Start-Stopwatch Show-StopwatchSummary Get-Stopwatch #> [CmdletBinding()] [OutputType([void], [PSCustomObject])] param( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [string]$Name, [Parameter()] [switch]$ShowElapsed, [Parameter()] [switch]$Quiet, [Parameter()] [switch]$PassThru ) process { # Initialize results dictionary if needed if (-not $Global:OrionStopwatchResults) { $Global:OrionStopwatchResults = @{} } # Check if the stopwatch was started if (-not $Global:OrionStopwatches -or -not $Global:OrionStopwatches.ContainsKey($Name)) { if (-not $Quiet) { Write-Warning "Stopwatch '$Name' was not started. Use Start-Stopwatch first." } return } # Calculate elapsed time $startTime = $Global:OrionStopwatches[$Name] $endTime = [DateTime]::Now $duration = $endTime - $startTime # Store the result $Global:OrionStopwatchResults[$Name] = [PSCustomObject]@{ Name = $Name StartTime = $startTime EndTime = $endTime Duration = $duration TotalSeconds = $duration.TotalSeconds } # Determine if we should display the elapsed time $shouldShow = $false if (-not $Quiet) { $shouldShow = $ShowElapsed -or ($Global:ShowStopwatchEnd -eq $true) } if ($shouldShow) { # Use Format-TimeSpan if available, otherwise format manually $formattedTime = if (Get-Command -Name 'Format-TimeSpan' -ErrorAction SilentlyContinue) { Format-TimeSpan -TimeSpan $duration } else { # Fallback formatting $totalSeconds = $duration.TotalSeconds if ($totalSeconds -lt 60) { "$([math]::Round($totalSeconds, 0)) sec" } else { $minutes = [int]($totalSeconds / 60) $seconds = [int]($totalSeconds % 60) "$minutes min $seconds sec" } } Write-Host "" Write-Host " ✓ " -ForegroundColor Green -NoNewline Write-Host "$Name" -ForegroundColor White -NoNewline Write-Host " completed in " -ForegroundColor DarkGray -NoNewline Write-Host "$formattedTime" -ForegroundColor Yellow } # Clean up the running stopwatch $Global:OrionStopwatches.Remove($Name) if ($PassThru) { return $Global:OrionStopwatchResults[$Name] } } } |