Test-NetConnection in Windows: the PowerShell replacement for ping, telnet and tracert

Test-NetConnection is the built-in PowerShell cmdlet that answers the three questions a sysadmin asks when something on the network stops working: can I reach the host at all, is the TCP port actually open, and which path does the traffic take. It ships with Windows in the NetTCPIP module, so there is nothing to install and nothing to enable.

That matters because the old toolset is either missing or misleading. The Telnet Client is an optional feature that is switched off on every modern Windows install, so the classic telnet host 443 port check fails before it starts. ping reports failure on hosts where ICMP is simply blocked by policy, and tracert gives you a hop list with no view of which local interface or source address Windows actually picked.

The official reference lists the parameters but not the decisions behind them. This article covers what each parameter set is genuinely useful for, how to read the source address and route fields that make multi-homed and VPN hosts diagnosable, and how to turn the cmdlet into scripted output instead of a wall of text. For the narrower question of which ports are listening on a machine, see how to check open ports on Windows.

Applies to: Windows 10 / 11 and Windows Server 2016 / 2019 / 2022 / 2025. The cmdlet first shipped with Windows 8.1 and Windows Server 2012 R2.


Quick answer

Two commands cover most of the daily work. The first replaces telnet and returns a full result object; the second returns a plain boolean, which is what you want inside a script or an if statement.

# Replaces "telnet sql01.corp.local 1433" - checks whether the TCP handshake completes
Test-NetConnection -ComputerName sql01.corp.local -Port 1433

# Same test, boolean only - Quiet suppresses the object and returns True or False
Test-NetConnection -ComputerName sql01.corp.local -Port 1433 -InformationLevel Quiet

The first command prints a six-field summary. TcpTestSucceeded is the line that answers the question.

ComputerName     : sql01.corp.local
RemoteAddress    : 10.20.0.31
RemotePort       : 1433
InterfaceAlias   : Ethernet0
SourceAddress    : 10.20.0.55
TcpTestSucceeded : True

What it does

The cmdlet has four parameter sets, and which one you land in depends entirely on the parameters you pass. This is the single most useful thing to internalise: with no port parameter it sends ICMP, with a port parameter it opens a TCP socket instead, and the two tests are never run together.

ParameterParameter setWhat it does
-ComputerNameallDNS name or IP address of the target. Positional, so it can be passed without the parameter name.
-PortRemotePortAny TCP port number. Switches the test from ICMP to a TCP connect.
-CommonTCPPortCommonTCPPortNamed shortcut. Accepted values: HTTP, RDP, SMB, WINRM.
-TraceRouteICMPRuns a trace to the target and fills the TraceRoute property.
-HopsICMPCaps the number of hops the trace will traverse.
-DiagnoseRoutingNetRouteDiagnosticsReports which route and source address the stack would select for this destination.
-ConstrainSourceAddressNetRouteDiagnosticsForces route selection to be evaluated from a given local IP address.
-ConstrainInterfaceNetRouteDiagnosticsSame, but constrained to an interface index.
-InformationLevelallAccepted values: Quiet and Detailed. Omit it for the standard summary.
Warning: -Port, -CommonTCPPort, -TraceRoute and -DiagnoseRouting belong to different parameter sets and cannot be combined. Asking for a port test and a trace route in one command is a parameter binding error, not a slow command.

Practical examples

1. Prove a firewall rule without installing telnet

The problem: An application on SRV-APP-02 cannot reach the SQL instance on sql01.corp.local and the network team says the rule is in place. You need evidence from the application server itself.

The solution: A TCP connect test from the exact host that is failing, which is what telnet used to do before it was removed from the default install.

Run this on SRV-APP-02. A completed handshake means the port is open end to end, including every firewall in the path. A failure prints a warning line before the object.

# tnc is the built-in short alias, useful when typing this into a live incident call
tnc sql01.corp.local -Port 1433
WARNING: TCP connect to (10.20.0.31 : 1433) failed
ComputerName     : sql01.corp.local
RemoteAddress    : 10.20.0.31
RemotePort       : 1433
InterfaceAlias   : Ethernet0
SourceAddress    : 10.20.0.55
TcpTestSucceeded : False
Result: RemoteAddress resolved, so DNS is fine. TcpTestSucceeded : False narrows the fault to the path or the listener, not to name resolution.

2. See which interface and source address Windows picked

The problem: A server with a management NIC and a production NIC reaches the domain controller intermittently, and you suspect traffic is leaving through the wrong adapter.

The solution: -InformationLevel Detailed adds the name resolution results and the selected next hop to the standard output, so you can see the routing decision instead of guessing at it.

# Detailed adds NameResolutionResults and NetRoute (NextHop) to the summary,
# which is what tells you the adapter choice rather than just the ping result
Test-NetConnection -ComputerName dc01.corp.local -InformationLevel Detailed
ComputerName           : dc01.corp.local
RemoteAddress          : 10.20.0.11
NameResolutionResults  : 10.20.0.11
InterfaceAlias         : Ethernet0
SourceAddress          : 10.20.0.55
NetRoute (NextHop)     : 10.20.0.1
PingSucceeded          : True
PingReplyDetails (RTT) : 1 ms

If InterfaceAlias names the management NIC when it should name the production NIC, the routing table is the problem, not the firewall.

3. Replace tracert and keep the hop list as data

The problem: Traffic to a remote site is slow and you want the hop list, but a broken path makes tracert sit through thirty hops of timeouts.

The solution: -TraceRoute with -Hops caps the trace, and the result is a string array you can index instead of screen text you have to read.

# -Hops 12 stops the trace early - a broken path otherwise costs 30 timeouts
$trace = Test-NetConnection -ComputerName 8.8.8.8 -TraceRoute -Hops 12

# TraceRoute is a plain array, so the first element is always the local gateway
$trace.TraceRoute[0]
$trace.TraceRoute.Count
10.20.0.1
9
Note: The trace uses ICMP. Hops that drop ICMP show as * in the array, exactly as they do in tracert output, and that is normal rather than a fault.

4. Check a list of ports in one pass

The problem: A new file and application server has to be validated against a firewall change request that lists five ports, and running five separate commands produces five screens of output nobody wants to compare.

The solution: Pipe the port list through ForEach-Object with -InformationLevel Quiet, and format one line per port.

$target = 'sql01.corp.local'

443,445,1433,3389,5985 | ForEach-Object {
    # Quiet returns a bare boolean; SilentlyContinue hides the red WARNING per failed port
    $ok = Test-NetConnection -ComputerName $target -Port $_ `
              -InformationLevel Quiet -WarningAction SilentlyContinue

    # {0,-6} left-aligns the port in a 6 character column so the states line up
    '{0,-6}{1}' -f $_, $(if ($ok) { 'open' } else { 'blocked' })
}
443   open
445   open
1433  blocked
3389  open
5985  open

The backtick at the end of the third line is the PowerShell line continuation character. It lets one command span two lines and must be the last character on the line, with no trailing space after it.

5. Report only the hosts that fail

The problem: After a firewall change you need to know which of twenty servers lost SMB, and reading twenty True values to find the one False is how mistakes happen.

The solution: Because Quiet returns a boolean, the whole test fits inside Where-Object and only the failures come back.

# -not inverts the boolean, so only hosts that failed the SMB test are emitted
'dc01','sql01','fs01' | Where-Object {
    -not (Test-NetConnection $_ -CommonTCPPort SMB `
              -InformationLevel Quiet -WarningAction SilentlyContinue)
}
fs01
Result: An empty result means every host passed. That makes the command safe to drop into a scheduled validation script, where silence is the success condition.

6. Diagnose route selection on a VPN or multi-homed host

The problem: A laptop on a split tunnel VPN can reach some internal subnets and not others, and the routing table alone does not make the winner obvious.

The solution: -DiagnoseRouting replaces the connectivity fields with route selection fields, so you see the decision rather than the outcome.

# Detailed is what exposes RouteSelectionEvents - without it the reasoning is hidden
Test-NetConnection -ComputerName 10.20.0.11 -DiagnoseRouting -InformationLevel Detailed

The fields worth reading are SelectedSourceAddress, OutgoingInterfaceIndex, SelectedNetRoute and RouteDiagnosticsSucceeded. If SelectedSourceAddress holds the physical adapter address while you expect the VPN address, the tunnel route is losing to a more specific local route.

-ConstrainSourceAddress then answers the follow-up question, which is whether the destination would be reachable if the stack had chosen the other address.

# Forces route selection to be evaluated as if traffic left the VPN address
Test-NetConnection -ComputerName 10.20.0.11 -DiagnoseRouting `
    -ConstrainSourceAddress 10.99.4.7 -InformationLevel Detailed

Hidden gems

PingSucceeded False does not mean the host is down. This is the single most misread result. A bare Test-NetConnection dc01.corp.local sends ICMP only, and most hardened Windows builds and nearly every cloud firewall drop ICMP by default. The host can be serving traffic perfectly while this field reads False. Always confirm with a port test before declaring a host unreachable.

# These two lines can legitimately disagree - the first is ICMP, the second is TCP
Test-NetConnection dc01.corp.local -InformationLevel Quiet
Test-NetConnection dc01.corp.local -Port 445 -InformationLevel Quiet
False
True

Quiet is the fast form, Detailed is the slow one. Detailed performs full name resolution and a route lookup on top of the connectivity test, which is noticeable when you loop over a host list. Use Quiet for anything that runs more than a handful of times and keep Detailed for the single host you are actually investigating.

The warning stream is separate from the result. A failed test writes a yellow WARNING line that is not part of the returned object, so it survives redirection and clutters logs. -WarningAction SilentlyContinue removes it without changing the result, which is why every scripted example above carries it.

There is no timeout parameter. A TCP test against a silently dropped port waits for the operating system connect timeout, which is roughly twenty seconds and cannot be shortened from the cmdlet. On PowerShell 7 the alternative is Test-Connection -TargetName host -TcpPort 1433 -TimeoutSeconds 2, which does accept one.


Cross-shell equivalent

The mapping below is the one to keep in mind when you inherit old scripts or move a check between platforms.

GoalLegacy CMDWindows PowerShell 5.1Linux shell
Reachabilityping hostTest-NetConnection hostping -c 4 host
TCP port opentelnet host 443Test-NetConnection host -Port 443nc -zv host 443
Path to targettracert hostTest-NetConnection host -TraceRoutetraceroute host
Boolean for a scriptparse %ERRORLEVEL%-InformationLevel Quietnc -z host 443 && echo up

On PowerShell 7 there is a second option that also runs on Linux and macOS. Test-Connection gained a TCP port mode and a real timeout, so cross-platform scripts should prefer it.

# PowerShell 7 only - returns True or False and gives up after 2 seconds
Test-Connection -TargetName sql01.corp.local -TcpPort 1433 -TimeoutSeconds 2

# PowerShell 7 traceroute equivalent, also cross-platform
Test-Connection -TargetName 8.8.8.8 -Traceroute
Note: Test-NetConnection lives in the Windows NetTCPIP module, so it exists on Windows only. Scripts that have to run on Linux or macOS need the Test-Connection form above.

Where this matters

  • Firewall change validation: run the port list before and after the change window and attach both outputs to the ticket.
  • Domain join and replication faults: confirm 445, 389 and 3268 to the domain controller before opening an Active Directory investigation.
  • WinRM and remoting setup: -CommonTCPPort WINRM separates a blocked port 5985 from an authentication failure in seconds.
  • Multi-homed servers: -DiagnoseRouting shows which adapter wins for a given destination, which the routing table alone rarely makes obvious.
  • Split tunnel VPN complaints: compare the selected source address against the VPN address to prove whether the tunnel route is being used.
  • Migration cutovers: a scheduled Where-Object check that emits nothing while everything is healthy makes a quiet mailbox the success signal.

Tips and limitations

  • No elevation is required for a normal test. The detailed TCP output reports IsAdmin and MatchingIPsecRules, and the IPsec rule list is only populated when the session is elevated.
  • TCP only. UDP services such as DNS on port 53 or syslog on 514 cannot be tested with this cmdlet.
  • -CommonTCPPort accepts exactly four values: HTTP, RDP, SMB and WINRM. Anything else needs -Port.
  • A successful TCP test proves the port is reachable and something is listening. It does not prove the service behind it is healthy or that the certificate is valid.
  • The cmdlet is Windows only. It is present in PowerShell 7 on Windows but has no Linux or macOS equivalent in the same module.
  • Parameter sets do not mix. One test per command, so a port check and a trace route are two separate invocations.

Official documentation


Related tools

  • Port Checker: tests a port from outside your network, which is the other half of the answer when the local test succeeds.
  • Network Diagnostics Tool: browser side checks to run alongside the local cmdlet during an incident.
  • DNS Lookup Tool: confirm the record independently when RemoteAddress resolves to something unexpected.

Related guides

  • How to check open ports on Windows: the listener side of the same problem, from the server rather than the client.
  • NETSTAT command: once a port test fails, netstat confirms whether anything is listening on the target at all.
  • NSLOOKUP command: use it when RemoteAddress resolves to the wrong host and the fault is DNS rather than the network.
  • IPCONFIG command: the local adapter and gateway view behind the InterfaceAlias and SourceAddress fields.