Public/network/Test-PortConnectivity.ps1
|
#Requires -Version 5.1 function Test-PortConnectivity { <# .SYNOPSIS Tests TCP port connectivity on one or more remote hosts. .DESCRIPTION Uses System.Net.Sockets.TcpClient to test whether specified TCP ports are reachable on target computers. Much faster than Test-NetConnection for bulk testing because it uses a configurable timeout and tests multiple port/host combinations sequentially. Returns structured objects suitable for pipeline processing and reporting. .PARAMETER ComputerName One or more target hostnames or IP addresses to test. Accepts pipeline input. .PARAMETER Port One or more TCP port numbers to test. Valid range: 1-65535. .PARAMETER TimeoutMs Connection timeout in milliseconds per port test. Default: 1000 (1 second). Valid range: 100-30000. .EXAMPLE Test-PortConnectivity -ComputerName 'SRV01' -Port 443 Tests if port 443 is open on SRV01. .EXAMPLE Test-PortConnectivity -ComputerName 'SRV01', 'SRV02' -Port 80, 443, 3389 Tests 3 ports on 2 servers (6 tests total). .EXAMPLE 'WEB01', 'WEB02', 'WEB03' | Test-PortConnectivity -Port 443, 8080 Pipeline input: tests 2 ports on 3 servers. .EXAMPLE Test-PortConnectivity -ComputerName '10.0.0.1' -Port 1..1024 -TimeoutMs 500 Scans ports 1-1024 on a host with a 500ms timeout. .OUTPUTS PSWinOps.PortConnectivity .NOTES Author: Franck SALLET Version: 1.0.0 Last Modified: 2026-03-21 Requires: PowerShell 5.1+ / Windows only Permissions: No admin required .LINK https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient #> [CmdletBinding()] [OutputType('PSWinOps.PortConnectivity')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [Alias('CN', 'Name', 'DNSHostName')] [string[]]$ComputerName, [Parameter(Mandatory = $true)] [ValidateRange(1, 65535)] [int[]]$Port, [Parameter(Mandatory = $false)] [ValidateRange(100, 30000)] [int]$TimeoutMs = 1000 ) begin { Write-Verbose "[$($MyInvocation.MyCommand)] Starting port connectivity tests (timeout: ${TimeoutMs}ms)" } process { foreach ($targetComputer in $ComputerName) { foreach ($targetPort in $Port) { $tcpClient = $null try { Write-Verbose "[$($MyInvocation.MyCommand)] Testing ${targetComputer}:${targetPort}" $tcpClient = New-Object System.Net.Sockets.TcpClient $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() $connectTask = $tcpClient.ConnectAsync($targetComputer, $targetPort) $completed = $connectTask.Wait($TimeoutMs) $stopwatch.Stop() if ($completed -and -not $connectTask.IsFaulted) { [PSCustomObject]@{ PSTypeName = 'PSWinOps.PortConnectivity' ComputerName = $targetComputer Port = $targetPort Protocol = 'TCP' Open = $true ResponseTimeMs = [math]::Round($stopwatch.Elapsed.TotalMilliseconds, 1) Timestamp = Get-Date -Format 'o' } } else { [PSCustomObject]@{ PSTypeName = 'PSWinOps.PortConnectivity' ComputerName = $targetComputer Port = $targetPort Protocol = 'TCP' Open = $false ResponseTimeMs = $null Timestamp = Get-Date -Format 'o' } } } catch { [PSCustomObject]@{ PSTypeName = 'PSWinOps.PortConnectivity' ComputerName = $targetComputer Port = $targetPort Protocol = 'TCP' Open = $false ResponseTimeMs = $null Timestamp = Get-Date -Format 'o' } } finally { if ($tcpClient) { $tcpClient.Close() $tcpClient.Dispose() } } } } } end { Write-Verbose "[$($MyInvocation.MyCommand)] Completed port connectivity tests" } } |