Public/Test-LissWindowsPathMtu.ps1
|
function Test-LissWindowsPathMtu { <# .SYNOPSIS Estimates an IPv4 path MTU without changing interface settings. .DESCRIPTION Confirms ordinary IPv4 ICMP response, then uses ping.exe with Don't Fragment and a bounded binary search. Every attempted payload is returned. The estimated MTU adds 28 bytes for IPv4 and ICMP headers to the largest successful payload. .PARAMETER Target Approved IPv4 destination hostname or address. .PARAMETER MinimumPayloadBytes Smallest ICMP payload considered by the binary search. .PARAMETER MaximumPayloadBytes Largest ICMP payload considered by the binary search. .PARAMETER TimeoutMilliseconds Timeout for each ping.exe attempt. .EXAMPLE Test-LissWindowsPathMtu -Target 1.1.1.1 -MinimumPayloadBytes 1200 -MaximumPayloadBytes 1472 #> [CmdletBinding()] [OutputType('LISSTech.WindowsNetworkDiagnostics.PathMtuResult')] param( [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$Target, [ValidateRange(0, 65507)][int]$MinimumPayloadBytes = 1200, [ValidateRange(0, 65507)][int]$MaximumPayloadBytes = 1472, [ValidateRange(100, 10000)][int]$TimeoutMilliseconds = 1000 ) if ($MinimumPayloadBytes -gt $MaximumPayloadBytes) { throw 'MinimumPayloadBytes cannot exceed MaximumPayloadBytes.' } $started = Get-Date $ordinary = Invoke-LissPingExecutable -Target $Target -PayloadBytes 32 -TimeoutMilliseconds $TimeoutMilliseconds if (-not $ordinary.Success) { return [pscustomobject]@{ PSTypeName = 'LISSTech.WindowsNetworkDiagnostics.PathMtuResult' Target = $Target StartedAt = $started CompletedAt = Get-Date Status = 'IcmpUnavailable' OrdinaryIcmpSuccessful = $false MinimumPayloadBytes = $MinimumPayloadBytes MaximumPayloadBytes = $MaximumPayloadBytes LargestSuccessfulPayload = $null EstimatedPathMtu = $null Attempts = @() Error = 'The target did not answer an ordinary IPv4 ICMP echo request.' } } $attempts = New-Object 'Collections.Generic.List[object]' $low = $MinimumPayloadBytes $high = $MaximumPayloadBytes $largestSuccess = $null while ($low -le $high) { $payload = [int][Math]::Floor(($low + $high) / 2) $probe = Invoke-LissPingExecutable -Target $Target -PayloadBytes $payload -TimeoutMilliseconds $TimeoutMilliseconds -DontFragment $attempts.Add([pscustomobject]@{ PayloadBytes = $payload Success = $probe.Success ExitCode = $probe.ExitCode Output = $probe.Output }) if ($probe.Success) { $largestSuccess = $payload $low = $payload + 1 } else { $high = $payload - 1 } } $status = if ($null -eq $largestSuccess) { 'NoSuccessfulProbe' } else { 'Estimated' } [pscustomobject]@{ PSTypeName = 'LISSTech.WindowsNetworkDiagnostics.PathMtuResult' Target = $Target StartedAt = $started CompletedAt = Get-Date Status = $status OrdinaryIcmpSuccessful = $true MinimumPayloadBytes = $MinimumPayloadBytes MaximumPayloadBytes = $MaximumPayloadBytes LargestSuccessfulPayload = $largestSuccess EstimatedPathMtu = if ($null -ne $largestSuccess) { $largestSuccess + 28 } else { $null } Attempts = $attempts.ToArray() Error = if ($status -eq 'NoSuccessfulProbe') { "Ordinary ICMP worked, but no Don't Fragment probe in the requested range succeeded." } else { $null } } } |