param( [string]$Scanner1Host = "192.168.1.13", [int]$Scanner1Port = 2001, [string]$Scanner2Host = "192.168.1.14", [int]$Scanner2Port = 2001, [int]$TimeoutMs = 5000, [switch]$Parallel ) $ErrorActionPreference = "Stop" function Test-TcpClientConnection { param( [Parameter(Mandatory = $true)] [string]$Name, [Parameter(Mandatory = $true)] [string]$HostName, [Parameter(Mandatory = $true)] [int]$Port, [Parameter(Mandatory = $true)] [int]$ConnectTimeoutMs ) $client = [System.Net.Sockets.TcpClient]::new() $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() try { Write-Host "[$Name] Connecting to $HostName`:$Port, TimeoutMs=$ConnectTimeoutMs ..." $connectTask = $client.ConnectAsync($HostName, $Port) $timeoutTask = [System.Threading.Tasks.Task]::Delay($ConnectTimeoutMs) $completedTask = [System.Threading.Tasks.Task]::WhenAny($connectTask, $timeoutTask).GetAwaiter().GetResult() $stopwatch.Stop() if ($completedTask -ne $connectTask) { return [pscustomobject]@{ Name = $Name Target = "$HostName`:$Port" Succeeded = $false ElapsedMs = $stopwatch.ElapsedMilliseconds LocalEndPoint = "" RemoteEndPoint = "" ErrorType = "Timeout" ErrorMessage = "ConnectAsync did not complete within $ConnectTimeoutMs ms." } } if ($connectTask.IsFaulted) { $exception = $connectTask.Exception.GetBaseException() return [pscustomobject]@{ Name = $Name Target = "$HostName`:$Port" Succeeded = $false ElapsedMs = $stopwatch.ElapsedMilliseconds LocalEndPoint = "" RemoteEndPoint = "" ErrorType = $exception.GetType().FullName ErrorMessage = $exception.Message } } return [pscustomobject]@{ Name = $Name Target = "$HostName`:$Port" Succeeded = $client.Connected ElapsedMs = $stopwatch.ElapsedMilliseconds LocalEndPoint = $client.Client.LocalEndPoint.ToString() RemoteEndPoint = $client.Client.RemoteEndPoint.ToString() ErrorType = "" ErrorMessage = "" } } catch { $stopwatch.Stop() return [pscustomobject]@{ Name = $Name Target = "$HostName`:$Port" Succeeded = $false ElapsedMs = $stopwatch.ElapsedMilliseconds LocalEndPoint = "" RemoteEndPoint = "" ErrorType = $_.Exception.GetType().FullName ErrorMessage = $_.Exception.Message } } finally { $client.Dispose() } } Write-Host "=== Scanner TCP Client Diagnostic ===" Write-Host "Machine: $env:COMPUTERNAME" Write-Host "User: $env:USERNAME" Write-Host "Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff')" Write-Host "Mode: $(if ($Parallel) { 'Parallel' } else { 'Sequential' })" Write-Host "" if ($Parallel) { $job1 = Start-Job -ScriptBlock ${function:Test-TcpClientConnection} -ArgumentList "Scanner1", $Scanner1Host, $Scanner1Port, $TimeoutMs $job2 = Start-Job -ScriptBlock ${function:Test-TcpClientConnection} -ArgumentList "Scanner2", $Scanner2Host, $Scanner2Port, $TimeoutMs $results = Receive-Job -Job $job1, $job2 -Wait Remove-Job -Job $job1, $job2 } else { $results = @( Test-TcpClientConnection -Name "Scanner1" -HostName $Scanner1Host -Port $Scanner1Port -ConnectTimeoutMs $TimeoutMs Test-TcpClientConnection -Name "Scanner2" -HostName $Scanner2Host -Port $Scanner2Port -ConnectTimeoutMs $TimeoutMs ) } foreach ($result in $results) { Write-Host "--- $($result.Name) ---" $result | Format-List } Write-Host "" Write-Host "Tip: if Sequential succeeds but Parallel times out, the device or network may reject concurrent short connections." Write-Host "Tip: close TCP debugging tools before running this script, because some scanners allow only one client connection."