リモートデスクトップやNAS、サーバーにつながらない時、「そもそも相手のポートまで通信が届いているのか」を確かめたいことがある。PowerShellなら、追加のソフトを入れなくても確認できる。
私は以前、仕事で複数のサーバーへの疎通確認をまとめて行うスクリプトを作った時に、SNMPのポート(161・162)をTest-NetConnectionで調べて、全部Falseになったことがある。SNMPはUDPなので、TCPしか調べられないTest-NetConnectionではFalseになって当然だった。この記事では、TCPの確認方法に加えて、UDPを確かめる方法もまとめる。
結論から書くと、TCPのポートはTest-NetConnectionに-Portを付けて実行し、TcpTestSucceededがTrueならつながる。UDPはTest-NetConnectionでは調べられないので、相手側で待ち受けているかを確認したうえで、実際にデータを送って返事が来るかで確かめる。
Test-NetConnection -ComputerName www.google.com -Port 443
この記事の実行例は、Windows 11のWindows PowerShell 5.1で実行したものだ。自分のPCやNASのIPアドレスは<PCのIP>のように書き換えている。
TCPのポートを確認する:Test-NetConnection -Port
-ComputerNameに相手のホスト名かIPアドレス、-Portにポート番号を指定する。Googleの443番(HTTPS)に試すと、次のようになった。
ComputerName : www.google.com RemoteAddress : 142.251.152.119 RemotePort : 443 InterfaceAlias : イーサネット SourceAddress : <PCのIP> TcpTestSucceeded : True
見るところはTcpTestSucceededだ。Trueなら、相手のそのポートにTCPで接続できている。ほかの項目の意味は次のとおり。
| 項目 | 意味 |
|---|---|
| ComputerName | 指定した相手 |
| RemoteAddress | 名前解決した相手のIPアドレス |
| RemotePort | 試したポート番号 |
| InterfaceAlias | 通信に使った自分のPCのネットワークアダプター |
| SourceAddress | 通信に使った自分のPCのIPアドレス |
| TcpTestSucceeded | TCPで接続できたか(True/False) |
うちのNAS(ファイル共有のSMBは445番)にも試してみた。
Test-NetConnection -ComputerName <NAS> -Port 445
ComputerName : <NAS> RemoteAddress : <NASのIP> RemotePort : 445 InterfaceAlias : イーサネット SourceAddress : <PCのIP> TcpTestSucceeded : True
NASの共有フォルダーが開けないのに445番がTrueなら、通信は届いていて、問題は認証やSMBの設定のほうにある、と切り分けられる。Windows 11 24H2以降でNASにつながらなくなった時の原因は、別の記事にまとめている。
よく使うポートは名前でも指定できる
-CommonTCPPortを使うと、ポート番号の代わりにHTTP・RDP・SMB・WINRMの4つを名前で指定できる。自分のPCのリモートデスクトップ(3389番)を確認するなら次のとおり。
Test-NetConnection -ComputerName localhost -CommonTCPPort RDP
ComputerName : localhost RemoteAddress : ::1 RemotePort : 3389 InterfaceAlias : Loopback Pseudo-Interface 1 SourceAddress : ::1 TcpTestSucceeded : True
つながらない時の出力と、時間がかかる理由
Googleの81番(使われていないポート)に試すと、次のようになった。
Test-NetConnection -ComputerName www.google.com -Port 81
TCP connect to (142.251.152.119 : 81) failed TCP connect to (142.251.154.119 : 81) failed TCP connect to (142.251.153.119 : 81) failed TCP connect to (142.251.156.119 : 81) failed TCP connect to (142.251.157.119 : 81) failed TCP connect to (142.251.150.119 : 81) failed TCP connect to (142.251.155.119 : 81) failed TCP connect to (142.251.151.119 : 81) failed TCP connect to (2001:4860:482c:7700:: : 81) failed TCP connect to (2001:4860:482b:7700:: : 81) failed TCP connect to (2001:4860:4828:7700:: : 81) failed TCP connect to (2001:4860:4826:7700:: : 81) failed TCP connect to (2001:4860:482a:7700:: : 81) failed TCP connect to (2001:4860:4829:7700:: : 81) failed TCP connect to (2001:4860:4827:7700:: : 81) failed TCP connect to (2001:4860:482d:7700:: : 81) failed ComputerName : www.google.com RemoteAddress : 142.251.152.119 RemotePort : 81 InterfaceAlias : イーサネット SourceAddress : <PCのIP> PingSucceeded : True PingReplyDetails (RTT) : 2 ms TcpTestSucceeded : False
TcpTestSucceededがFalseになり、ポートに接続できなかった時は、PingSucceeded(pingが通ったか)も表示される。ここがTrueでTCPがFalseなら、「相手までは届いているが、そのポートには接続できない」ということになる。ただし、pingを返さない設定の機器も多いので、PingSucceededがFalseでも相手まで届いていないとは限らない。
気をつけたいのは時間だ。この1回で約169秒かかった。TCP connect to ... failedの行を見ると、www.google.comの名前解決で返ってきたIPアドレス16個(IPv4が8個、IPv6が8個)すべてに順番に接続を試している。1つの名前に複数のIPアドレスがある相手だと、失敗した時にとても待たされる。急ぐ時は、後で書くタイムアウトを短くした確認方法を使うとよい。
ホスト名が間違っていて名前解決できない時は、次のようにすぐ終わる。TCPの結果は出ず、RemoteAddressも空になる。
Name resolution of no-such-host.invalid failed ComputerName : no-such-host.invalid RemoteAddress : InterfaceAlias : SourceAddress : PingSucceeded : False
Falseになった時に疑うところ
- 相手側で、そのポートを使うサービスが動いていない(この後の「相手側で待ち受けているか確認する」で確かめられる)
- 相手側のWindowsファイアウォールなどで、そのポートへの受信が許可されていない
- 途中のルーターやファイアウォール、VPNで止められている
- そもそもUDPのポートを調べている(
Test-NetConnectionはTCPしか調べられない)
Tailscale経由のリモートデスクトップがつながらない時の確認ポイントは、別の記事にまとめている。
True/Falseだけ欲しい時:-InformationLevel Quiet
スクリプトの中で使うなら、-InformationLevel Quietを付けると結果がTrueかFalseだけになる。
Test-NetConnection -ComputerName www.google.com -Port 443 -InformationLevel Quiet
443番ではTrueだけが返ってきた。81番で試すと、TCP connect to ... failedの行は表示されたうえで、最後にFalseが返ってきた。かかった時間は約169秒で、Quietにしても速くはならない。
逆に、どこを通って通信しているかまで見たい時は-InformationLevel Detailedを付ける。名前解決の結果(NameResolutionResults)や、次に渡すルーター(NetRoute (NextHop))も表示される。
Test-NetConnection -ComputerName www.google.com -Port 443 -InformationLevel Detailed
タイムアウトを短くして確認する(複数のポートもまとめて)
Test-NetConnectionはタイムアウトを指定できない。待たされたくない時は、.NETのTcpClientで接続を試して、決めた時間で打ち切る。次は1秒(1000ミリ秒)で打ち切る関数だ。
function Test-TcpPort($ComputerName, $Port, $TimeoutMs = 1000) {
$client = New-Object System.Net.Sockets.TcpClient
try {
$client.ConnectAsync($ComputerName, $Port).Wait($TimeoutMs)
} catch {
$false
} finally {
$client.Dispose()
}
}
Test-TcpPort www.google.com 443
Test-TcpPort www.google.com 81
時間内に接続できればTrue、できなければFalseが返る。私の環境では443番はTrue、81番は1秒でFalseになった。Test-NetConnectionで約169秒かかった81番が、1秒で終わる。
複数のポートをまとめて確認するなら、上の関数を読み込んだ状態で次のようにする。
foreach ($p in 80, 443, 81) {
[pscustomobject]@{ Port = $p; Open = (Test-TcpPort www.google.com $p) }
}
Port Open ---- ---- 80 True 443 True 81 False
相手が遠い・回線が遅いと、1秒では足りずにFalseになることもある。Falseが出たら、$TimeoutMsを3000などに延ばしてもう一度試すとよい。複数のサーバーをCSVから読み込んで一括で確認するスクリプトは、以前の記事に載せている。
PowerShell 7ならTest-Connection -TcpPortも使える(試していない)
PowerShell 7では、Test-Connectionに-TcpPortを付けてTCPの接続を確認でき、結果はTrue/Falseで返る。タイムアウトは-TimeoutSecondsで指定でき、既定は5秒だ(Microsoft Learnのドキュメントより)。私のPCにはPowerShell 7を入れていないので、試していない。
Test-Connection www.google.com -TcpPort 443
相手側で待ち受けているか確認する:Get-NetTCPConnection
相手もWindowsで、相手のPCを操作できるなら、相手側でそのポートを待ち受けているか(Listen)を確認する。ここで何も出なければ、通信経路ではなく、サービスが動いていないことが原因だ。リモートデスクトップの3389番なら次のとおり。
Get-NetTCPConnection -LocalPort 3389 -State Listen
LocalAddress LocalPort RemoteAddress RemotePort State AppliedSetting OwningProcess ------------ --------- ------------- ---------- ----- -------------- ------------- :: 3389 :: 0 Listen 2204 0.0.0.0 3389 0.0.0.0 0 Listen 2204
LocalAddressが0.0.0.0(IPv4)や::(IPv6)なら、PCのすべてのIPアドレスで待ち受けている。127.0.0.1だけになっている場合は、そのPCの中からしか接続できない。
どのプログラムが待ち受けているかも見たい時は、OwningProcess(プロセスID)からプロセス名を出す。
Get-NetTCPConnection -LocalPort 3389 -State Listen | Select-Object LocalAddress, LocalPort, State, OwningProcess, @{n='ProcessName';e={(Get-Process -Id $_.OwningProcess).ProcessName}}
私のPCではsvchostと表示された。リモートデスクトップはサービスとして動いているので、svchostになる。この確認は、管理者でないPowerShellでもできた。
UDPのポートを確認する
UDPがTCPと同じように確認できないのは、UDPには「接続」がないからだ。TCPは接続できたかどうかで判断できるが、UDPはデータを送りっぱなしにするだけなので、相手に届いたかどうかは、相手が何か返してくれないと分からない。しかも、多くのサービスは決まった形式のデータにしか返事をしない。
Microsoftのポート確認ツールPortQryの説明でも、UDPのポートから応答がない場合は「LISTENING または FILTERED」(待ち受けているのか、途中で止められているのか判別できない)と報告する、とされている。そこで、UDPは次の順番で確かめる。
確認1:相手側で待ち受けているか(Get-NetUDPEndpoint)
相手側のWindowsで、そのUDPポートを開いているプログラムがあるかを確認する。
Get-NetUDPEndpoint -LocalPort 3389
LocalAddress LocalPort ------------ --------- :: 3389 0.0.0.0 3389
リモートデスクトップは、TCPだけでなくUDPの3389番も使っている。同じように、Tailscaleが既定で使うUDPの41641番も、私のPCでは待ち受けていた。
Get-NetUDPEndpoint -LocalPort 41641
ここで表示されれば、相手側でプログラムがそのポートを開いている。ただし、これだけでは自分のPCから届くかどうかは分からない。
確認2:そのサービスに実際に問い合わせる(DNSの例)
相手のサービスが返事をする問い合わせを送れるなら、それが一番確実だ。たとえばDNS(UDPの53番)なら、Resolve-DnsNameで問い合わせ先のサーバーを指定すればよい。
Resolve-DnsName -Name www.google.com -Server 8.8.8.8 -DnsOnly -Type A
Name Type TTL Section IPAddress ---- ---- --- ------- --------- www.google.com A 186 Answer 142.251.150.119 www.google.com A 186 Answer 142.251.154.119 (以下略)
答えが返ってくれば、8.8.8.8のUDP 53番まで届いて、返事も戻ってきている。DNSサーバーがいない宛先(説明用のアドレス192.0.2.1)を指定すると、約7秒後に次のエラーになった。
Resolve-DnsName : www.google.com : This operation returned because the timeout period expired
ほかのサービス(SNMPなど)も、そのサービス用のコマンドやツールで問い合わせて、返事が来るかで確かめるのが基本になる。
確認3:PowerShellで送受信を試す(両方のPCを操作できる時)
サービスに問い合わせる方法がない時や、サービスを動かす前に経路だけ確かめたい時は、相手側で受信用のPowerShellを動かし、自分側から送ってみる。相手側で受け取ったデータをそのまま送り返すので、自分側で返事が見えれば、行きも帰りも届いている。
相手側(受け取る側)で実行する。ポート番号の50000は例なので、確かめたい番号に変える。そのポートを使うサービスが動いていると同じ番号では待ち受けられないので、サービスを止めるか、空いている番号で経路を確かめる。
$port = 50000 $udp = New-Object System.Net.Sockets.UdpClient $port $udp.Client.ReceiveTimeout = 60000 $remote = New-Object System.Net.IPEndPoint ([System.Net.IPAddress]::Any, 0) $data = $udp.Receive([ref]$remote) $udp.Send($data, $data.Length, $remote) | Out-Null $udp.Close() "受信: " + [Text.Encoding]::UTF8.GetString($data) + " from " + $remote
60秒(60000ミリ秒)待っている間に、自分側(送る側)で次を実行する。$targetには相手のIPアドレスを入れる。
$target = "192.168.1.10"
$port = 50000
$udp = New-Object System.Net.Sockets.UdpClient
$udp.Client.ReceiveTimeout = 3000
$bytes = [Text.Encoding]::UTF8.GetBytes("hello")
$udp.Send($bytes, $bytes.Length, $target, $port) | Out-Null
$remote = New-Object System.Net.IPEndPoint ([System.Net.IPAddress]::Any, 0)
try {
"応答: " + [Text.Encoding]::UTF8.GetString($udp.Receive([ref]$remote))
} catch {
"応答なし: " + $_.Exception.Message
} finally {
$udp.Close()
}
私は1台のPCの中で試した(受け取る側をバックグラウンドジョブで動かし、送る側の$targetを127.0.0.1にした)。送る側に応答: hello、受け取る側に受信: hello from 127.0.0.1:50818のように表示された。別のPCとの間では試していない。相手側のWindowsファイアウォールで、受け取る側のPowerShellへの受信が止められていると届かないので、その場合はファイアウォールの許可も確認する。
受け取る側を動かさずに送ると、送る側には次のように表示された。
応答なし: Exception calling "Receive" with "1" argument(s): "An existing connection was forcibly closed by the remote host"
「接続が強制的に切断された」というメッセージだが、UDPなので接続が切れたわけではない。相手から「そのポートで待ち受けているプログラムはない」という知らせ(ICMPの「ポートに到達できない」)が返ってきた時に、こう表示される。PortQryの説明でも、この知らせが返ってきた場合は「NOT LISTENING」(待ち受けていない)と判断している。一方、途中のファイアウォールで捨てられた場合は何も返ってこないので、3秒待ってタイムアウトのエラーになるはずだ(こちらは試していない)。
PortQryを使う方法(試していない)
Microsoftが配布しているPortQryというツールを使うと、TCPとUDPのポートを調べられる。DNSやLDAP、SNMPなど一部のサービスには、そのサービス用の問い合わせを送って、待ち受けているかを判断してくれる。PowerShellのコマンドではなく、別途ダウンロードが必要だ。私は使っていないので、詳しくはMicrosoftの説明を見てほしい。
portqry -n 192.168.1.10 -p udp -e 161
まとめ
| 確認したいこと | コマンド |
|---|---|
| TCPのポートにつながるか | Test-NetConnection -ComputerName 相手 -Port 番号 |
| True/Falseだけ欲しい | -InformationLevel Quietを付ける |
| 待たされずに確認したい | TcpClientでタイムアウトを指定する(この記事のTest-TcpPort) |
| 相手側でTCPを待ち受けているか | Get-NetTCPConnection -LocalPort 番号 -State Listen |
| 相手側でUDPを待ち受けているか | Get-NetUDPEndpoint -LocalPort 番号 |
| UDPが届くか | サービスに問い合わせる(DNSならResolve-DnsName -Server)か、PowerShellで送受信を試す |
Test-NetConnectionで調べられるのはTCPだけだ。UDPのポートをFalseで「つながらない」と判断しないように気をつけたい。
関連記事
- 【PowerShell】複数サーバへのPingとTCPポートの疎通確認を一括で実行する
- 【Windows】Tailscaleでリモートデスクトップがつながらない時の確認ポイント
- 【Windows】Windows11 24H2/25H2で共有フォルダ・NASにアクセスできない原因と対処|ゲストアクセスとSMB署名

コメント