Public/Measure-LissWindowsBufferbloat.ps1
|
function Measure-LissWindowsBufferbloat { <# .SYNOPSIS Compares idle and loaded endpoint latency with approved iperf3 load. .DESCRIPTION Collects an idle ICMP baseline, starts the bundled signed iperf3 client or an explicitly selected approved executable without blocking redirected output, samples latency concurrently with upload or download load, and returns latency increases plus parsed iperf3 JSON. It cleans up the child process after success or failure. This consumes bandwidth and requires -Approved plus ShouldProcess confirmation. .PARAMETER Server Approved iperf3 server hostname or address. .PARAMETER LatencyTarget Endpoint used for idle and loaded ICMP latency sampling. .PARAMETER Port Approved iperf3 server port. .PARAMETER Direction Upload or Download load direction. .PARAMETER DurationSeconds Loaded test duration, from 5 through 120 seconds. .PARAMETER IdleDurationSeconds Idle baseline duration, from 1 through 30 seconds. .PARAMETER IntervalMilliseconds Latency sampling interval. .PARAMETER TimeoutMilliseconds Timeout for each ICMP sample. .PARAMETER IperfPath Optional path to another approved iperf3 executable. The signed bundled x64 client is used by default. .PARAMETER Approved Confirms that the server and bandwidth use are approved. .EXAMPLE Measure-LissWindowsBufferbloat -Server iperf.internal.example -LatencyTarget 1.1.1.1 -Direction Download -Approved -Confirm:$false #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] [OutputType('LISSTech.WindowsNetworkDiagnostics.BufferbloatResult')] param( [Parameter(Mandatory)][ValidatePattern('^[a-zA-Z0-9][a-zA-Z0-9._:-]*$')][string]$Server, [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$LatencyTarget, [ValidateRange(1, 65535)][int]$Port = 5201, [ValidateSet('Upload', 'Download')][string]$Direction = 'Upload', [ValidateRange(5, 120)][int]$DurationSeconds = 10, [ValidateRange(1, 30)][int]$IdleDurationSeconds = 5, [ValidateRange(50, 5000)][int]$IntervalMilliseconds = 250, [ValidateRange(100, 10000)][int]$TimeoutMilliseconds = 1000, [string]$IperfPath, [Parameter(Mandatory)][switch]$Approved ) if (-not $Approved) { throw 'Explicit -Approved confirmation is required for bufferbloat testing.' } $executable = Resolve-LissIperfExecutable -Path $IperfPath $target = "$Direction load from approved server $Server`:$Port with latency target $LatencyTarget" if (-not $PSCmdlet.ShouldProcess($target, 'Run concurrent iperf3 and ICMP test')) { return } $started = Get-Date $idleSamples = @(Invoke-LissLatencyWindow -Target $LatencyTarget -DurationSeconds $IdleDurationSeconds -IntervalMilliseconds $IntervalMilliseconds -TimeoutMilliseconds $TimeoutMilliseconds) $idleSummary = Get-LissLatencySummary -Sample $idleSamples -Target $LatencyTarget $context = $null try { $context = Start-LissIperfLoad -Executable $executable -Server $Server -Port $Port -DurationSeconds $DurationSeconds -Direction $Direction $loadedSamples = @(Invoke-LissLatencyWindow -Target $LatencyTarget -DurationSeconds $DurationSeconds -IntervalMilliseconds $IntervalMilliseconds -TimeoutMilliseconds $TimeoutMilliseconds -WhileProcessRuns $context.Process) $iperfResult = Complete-LissIperfLoad -Context $context -DurationSeconds $DurationSeconds $context = $null } finally { if ($context) { Stop-LissProcessContext -Context $context if ($context.Process) { $context.Process.Dispose() } if ($context.WorkingDirectory -and [IO.Directory]::Exists($context.WorkingDirectory)) { [IO.Directory]::Delete($context.WorkingDirectory, $true) } } } $loadedSummary = Get-LissLatencySummary -Sample $loadedSamples -Target $LatencyTarget [pscustomobject]@{ PSTypeName = 'LISSTech.WindowsNetworkDiagnostics.BufferbloatResult' Server = $Server Port = $Port Direction = $Direction LatencyTarget = $LatencyTarget StartedAt = $started CompletedAt = Get-Date IdleLatency = $idleSummary LoadedLatency = $loadedSummary AverageLatencyIncreaseMilliseconds = if ($null -ne $idleSummary.AverageMilliseconds -and $null -ne $loadedSummary.AverageMilliseconds) { [Math]::Round($loadedSummary.AverageMilliseconds - $idleSummary.AverageMilliseconds, 2) } else { $null } Percentile95IncreaseMilliseconds = if ($null -ne $idleSummary.Percentile95Milliseconds -and $null -ne $loadedSummary.Percentile95Milliseconds) { [Math]::Round($loadedSummary.Percentile95Milliseconds - $idleSummary.Percentile95Milliseconds, 2) } else { $null } IdleSamples = $idleSamples LoadedSamples = $loadedSamples IperfResult = $iperfResult } } |