Private/Test-WinClatIcmp.ps1
|
Function Test-WinClatIcmp { <# .SYNOPSIS Runs the ICMP functional test against an IPv4 target. .DESCRIPTION Sends up to three ICMP echo requests with System.Net.NetworkInformation.Ping, each with a two-second timeout (DESIGN.md, section 8.4): - An echo reply returns Pass. - A destination unreachable response returns Pass, because a translated reply proves the CLAT path. - No response to any attempt returns Warning; the target may be unreachable or filtered. - Any other status, or an exception, returns Fail, because it means there is no working IPv4 path. Returns an object with Result and Detail. Detail records the method and target. This function must also be available in the remote session. See DESIGN.md, section 4.3. .PARAMETER Target The IPv4 address to test. Validated by Test-WinClatIPv4Target before it reaches this function. .PARAMETER Attempts The maximum number of echo requests. The default is 3. .PARAMETER TimeoutMilliseconds The timeout for each echo request. The default is 2000. .INPUTS None. This function does not accept pipeline input. .OUTPUTS System.Management.Automation.PSCustomObject with Result and Detail properties. .EXAMPLE Test-WinClatIcmp -Target '192.0.2.10' Returns Result Pass when 192.0.2.10 answers an echo request. .LINK https://learn.microsoft.com/dotnet/api/system.net.networkinformation.ping .NOTES Version: 1.0.0 Creation Date: October 28, 2026 Last Updated: October 28, 2026 Author: Richard Hicks Organization: Richard M. Hicks Consulting, Inc. Contact: rich@richardhicks.com Website: https://www.richardhicks.com/ #> [CmdletBinding()] [OutputType([PSCustomObject])] Param ( [Parameter(Mandatory)] [string]$Target, [ValidateRange(1, 10)] [int]$Attempts = 3, [ValidateRange(100, 60000)] [int]$TimeoutMilliseconds = 2000 ) $Unreachable = @('DestinationUnreachable', 'DestinationHostUnreachable', 'DestinationNetworkUnreachable', 'DestinationPortUnreachable', 'DestinationProtocolUnreachable', 'DestinationProhibited') $Ping = New-Object -TypeName System.Net.NetworkInformation.Ping Try { For ($Attempt = 1; $Attempt -le $Attempts; $Attempt++) { Try { $Reply = $Ping.Send($Target, $TimeoutMilliseconds) } Catch { $Message = $_.Exception.Message If ($_.Exception.InnerException) { $Message = $_.Exception.InnerException.Message } Return [PSCustomObject]@{ Result = 'Fail'; Detail = "ICMP echo to ${Target}: the request failed ($Message). There is no working IPv4 path." } } $Status = [string]$Reply.Status If ($Status -eq 'Success') { Return [PSCustomObject]@{ Result = 'Pass'; Detail = "ICMP echo to ${Target}: reply in $($Reply.RoundtripTime) ms (attempt $Attempt of $Attempts)." } } If ($Unreachable -contains $Status) { Return [PSCustomObject]@{ Result = 'Pass'; Detail = "ICMP echo to ${Target}: $Status returned. A translated reply proves the CLAT path." } } If ($Status -ne 'TimedOut') { Return [PSCustomObject]@{ Result = 'Fail'; Detail = "ICMP echo to ${Target}: $Status. There is no working IPv4 path." } } } [PSCustomObject]@{ Result = 'Warning'; Detail = "ICMP echo to ${Target}: no reply after $Attempts attempts of $TimeoutMilliseconds ms. The target may be unreachable or filtered." } } Finally { $Ping.Dispose() } } |