「通信が通らない」の切り分けで困るのは、パケットが消えた場所が分からないことです。相手まで届いていないのか、届いたが捨てられたのか、自分のPCの中で落ちているのか。
業務PCにWiresharkを入れられない現場も多いですが、Windows 10 1809以降には pktmon が標準で入っています。しかも、Wiresharkには無い機能があります。

パケットが通るコンポーネントを階層で見せ、どこで、どんな理由で落ちたかを教えてくれます。この記事は Windows 11(build 26200)での実測です。
1. まず、すべて管理者権限が要る
最初につまずくのがここです。
pktmon list
PktMon ドライバーとの通信に失敗しました: アクセスが拒否されました。
一覧を見るだけの list も、状態を見るだけの status も落ちます。 管理者権限で開いたPowerShellでないと、1つも動きません。
# 昇格したウィンドウを開く
Start-Process powershell -Verb RunAs
2. list と list --all は別物
pktmon list はネットワークアダプターの一覧です。
ID MAC アドレス 名前
14 00-11-22-33-44-55 Intel(R) Ethernet Controller (3) I225-V
18 Wintun Userspace Tunnel
139 00-11-22-33-44-55 vEthernet (LAN)
142 00-15-5D-AA-BB-01 vEthernet (Default Switch)
145 00-15-5D-AA-BB-02 vEthernet (WSL (Hyper-V firewall))
物理NIC(14)と vEthernet(139)のMACが同じなのは、Hyper-Vの仮想スイッチが物理NICのMACを引き継ぐためです。
本番はこちらです。
pktmon list --all
vSwitch: LAN
ID: 138
NIC: Intel(R) Ethernet Controller (3) I225-V
ID: 14
ドライバー: e2f.sys
ifIndex: 10
フィルター ドライバー:
36 wfplwfs.sys WFP Native Filter
プロトコル:
94 vmswitch.sys VMS Protocol * (すべて)
89 mslldp.sys MSLLDP LLDP
NIC: vEthernet (LAN)
ID: 139
ドライバー: vmswitch.sys
ifIndex: 8
フィルター ドライバー:
39 wfplwfs.sys WFP Native Filter
38 pacer.sys QoS Packet Scheduler
37 wfplwfs.sys WFP 802.3 Filter
プロトコル:
97 tcpip.sys TCPIP6 IPv6
96 tcpip.sys TCPIP IPv4, ARP
パケットが通るドライバが、.sys のファイル名つきで全部並びます。これが pktmon の一番の価値だと思います。
VPNクライアントやEDR、ウイルス対策ソフトがNDISフィルタとして割り込んでいる場合、ここに名前が出ます。 「何かが通信を邪魔している気がする」を、製品名で確認できます。
物理NICが ifIndex 10、vEthernet が ifIndex 8 という対応も読み取れます。Windowsで通信が思った経路を通らないで触れた「物理NICにIPアドレスが付いていない」状態は、この構造が原因です。
3. counters でコンポーネント別のドロップ数を見る
ログを書かずにカウンターだけ取る方法があります。
# --counters-only ならログファイルを作らない。いちばん軽い
pktmon start --capture --counters-only
# (ここで再現操作をする)
pktmon counters
pktmon stop
実測の抜粋です。
vSwitch: LAN
ID 名前 カウンター 方向 パケット バイト
14 Intel(R) Ethernet C... ドロップ Rx 470 101,073
Upper Rx 377 69,777
36 WFP Native Filter Lower Rx 470 101,073
139 vEthernet (LAN) ドロップ エグレス 3 369
97 TCPIP6 ドロップ Rx 126 26,564
96 TCPIP ドロップ Rx 313 64,523
Lower と Upper は、そのコンポーネントの下側と上側です。両者の差が、そのコンポーネントで消えた分になります。上の例なら物理NICで Rx 470 入って Upper 377 しか上がっていません。
8秒のpingの裏でこれだけ落ちています。平常時でもドロップは常にあるので、「ドロップがある=異常」ではありません。再現操作の前後で数えて、増えた分を見るのが正しい使い方です。
4. --type drop なら理由が付く
ここがWiresharkとの決定的な違いです。
# 落ちたパケットだけを、全長(--pkt-size 0)で記録する
pktmon start --capture --type drop --pkt-size 0 --file-name C:\temp\drops.etl
# (再現操作)
pktmon stop
pktmon etl2txt C:\temp\drops.etl --out C:\temp\drops.txt
出力の1件はこうなります。
ドロップ: PktGroupId 8348、PktNumber 1、外部 0、方向 Rx 、種類 IP 、
コンポーネント 126、フィルター 0、Not locally destined 、
ドロップ: ip: 192.168.10.104.50160 > 239.255.255.251.50160: UDP, length 547
「コンポーネント 126 が Not locally destined で落とした」まで書いてあります。実測で拾えた理由を数えました。

| 件数 | 理由 | 意味 |
|---|---|---|
| 875 | Unsupported EtherType | そのコンポーネントが扱わない種別 |
| 50 | INET: session state error | TCPの状態と合わないセグメント |
| 14 | INET: transport endpoint was not found | 待ち受けているプロセスが無い |
| 11 | Not locally destined | 自分宛てではない |
| 4 | INET: duplicate segment | 再送などの重複 |
| 3 | ARP: not locally destined | 自分宛てでないARP |
| 2 | INET: received RST | 相手からRSTが返った |
| 1 | Port unreachable | ポートが閉じている |
切り分けで効くのは太字の行です。transport endpoint was not found が出ていれば、ファイアウォールではなく「アプリが起動していない・別ポートで待っている」と分かります。ここを取り違えると、ファイアウォールの設定を延々と見直すことになります。
ドロップのログに出るコンポーネント番号は
pktmon listには載っていないことがあります(上の126もそうです)。アダプタしか出ないためで、pktmon list --allと突き合わせてください。
5. Wiresharkへ渡すなら etl2pcap
サブコマンド名は pcapng ではなく etl2pcap です。
pktmon etl2pcap C:\temp\drops.etl --out C:\temp\drops.pcapng
ただし--type drop で取ったものを変換したら、156バイトのほぼ空のファイルになりました(テキスト側は3,018行取れています)。Wiresharkで中身を見たいときは、--type drop ではなく通常のキャプチャで取るほうが確実です。
6. フィルタで絞る
pktmon filter remove # 既存を全部消してから
pktmon filter add 'icmp-only' --transport-protocol ICMP
pktmon filter add 'dns-only' --port 53
pktmon filter list
# 名前 プロトコル ポート
1 icmp-only ICMP
2 dns-only 53
フィルタは明示的に消すまで残ります。 調査が終わったら pktmon filter remove を忘れないでください。次の人が「なぜか特定の通信しか取れない」で悩みます。
7. 取った後の取り扱いに注意
実測して気づいたのですが、キャプチャには想像以上に他人の情報が入ります。
- 同じLANにいる別の機器のMACアドレス(マルチキャストやブロードキャストの送信元)
- 自分のPCのグローバルIPv6アドレス(プレフィックスから契約回線が分かる)
- 接続先のIPアドレスとポート(どのサービスを使っているか)
ベンダーに送る前、チケットに添付する前に中身を確認してください。 社内のトラブルシューティングのつもりが、社外に経路情報を渡すことになります。
もう1つ、PowerShellで出力をファイルに残すときの罠があります。
# やってはいけない:ファイルまで40行で切れる
pktmon list --all | Tee-Object -FilePath out.txt | Select-Object -First 40
# 正しい:ファイルに書いてから、表示だけ絞る
pktmon list --all | Out-File out.txt
Get-Content out.txt -TotalCount 40
Select-Object -First は上流のパイプラインに停止を伝えるので、Tee-Object の書き込みごと打ち切られます。実際にこれで一覧の後半(別の仮想スイッチの分)を失いました。
なお Out-File と Tee-Object の既定の文字コードは、Windows PowerShell 5.1 では UTF-16 です。findstr や grep で検索できないので、-Encoding utf8 を付けておくと後が楽です。
8. まとめ
pktmonは Windows 10 1809以降に標準搭載。 インストール不要- すべてのサブコマンドが管理者権限必須。
listもstatusも落ちる pktmon listはアダプタだけ。list --allで全階層がドライバ名つきで出る- 割り込んでいるNDISフィルタが製品名で分かる。 これは他のツールには無い
countersのLowerとUpperの差が、そこで消えた分- 平常時でもドロップはある。 再現操作の前後で増分を見る
--type dropなら理由が付く。transport endpoint was not foundならアプリ側- 変換は
etl2pcap(pcapngではない) - フィルタは消すまで残る。 終わったら
pktmon filter remove - キャプチャには他人のMACと自分のグローバルIPv6が残る。 渡す前に確認する
Wiresharkが入れられない現場でも、「どこで落ちたか」だけならこれで十分だと思います。

コメント