Windows PowerShell で Bash の kill lsof 相当を行う

Linux・Bash の世界だと、lsof コマンドでそのポート番号を使っているプロセスを調べて、ps で実行コマンドを調べたり kill したり、といったことができる。

# 8080 ポートを使っているプロセス ID は? → PID 995 と判明
$ lsof -i:8080
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
MainThrea 995  neo   21u  IPv6  21578      0t0  TCP *:tproxy (LISTEN)

# PID 995 は何のコマンドが動いてる?
$ ps 995
PID TTY      STAT   TIME COMMAND
995 pts/4    Sl+    0:00 node index.js

# `lsof` コマンドは PID だけを出力できる (`-t` オプション)
$ lsof -i:8080 -t
995

# `kill` コマンドに流し込めば一発でタスクキルできる
$ kill $(lsof -i:8080 -t)

コレと同等のことを、Windows 環境・PowerShell でやりたかったので、調べた。

# 方法 1 : `netstat` を使う
PS> netstat -ano | Select-String '0.0.0.0:8080'
  TCP         0.0.0.0:8080           0.0.0.0:0              LISTENING       7064

# `netstat` で PID だけ取り出す
PS> netstat -ano | Select-String '0.0.0.0:8080' | ForEach-Object { ($_ -split '\s+')[-1] }
7064

# 方法 2 : `Get-NetTCPConnection` で一発で取れる
PS> Get-NetTCPConnection -LocalPort 8080
LocalAddress                        LocalPort RemoteAddress                       RemotePort State       AppliedSetting
------------                        --------- -------------                       ---------- -----       --------------
::                                  8080      ::                                  0          Listen                    

# PID だけ取り出す
PS> Get-NetTCPConnection -LocalPort 8080 | Select-Object -ExpandProperty OwningProcess
7064

# PID を指定して実行されているコマンドを調べる
PS> Get-CimInstance Win32_Process -Filter 'ProcessId = 7064' | Select-Object ProcessId, Name, CommandLine
ProcessId Name     CommandLine
--------- ----     -----------
     7064 node.exe C:\nvm4w\nodejs\node.exe index.js

# ポート番号から直接実行コマンドを調べる
PS> Get-NetTCPConnection -LocalPort 8080 | ForEach-Object { Get-CimInstance Win32_Process -Filter 'ProcessId = $($_.OwningProcess)' } | Select ProcessId, Name, CommandLine
ProcessId Name     CommandLine
--------- ----     -----------
     7064 node.exe C:\nvm4w\nodejs\node.exe index.js


# ポート番号を指定してタスクキルに持ち込むなら以下のいずれかで良い
PS> netstat -ano | Select-String '0.0.0.0:8080' | ForEach-Object { ($_ -split '\s+')[-1] } | ForEach-Object { Stop-Process -Id $_ -Force }
PS> Stop-Process -Id (Get-NetTCPConnection -LocalPort 8080).OwningProcess -Force
PS> Stop-Process -Id (Get-NetTCPConnection -LocalPort 8080 | Select-Object -ExpandProperty OwningProcess) -Force

個人的には

PS> Get-NetTCPConnection -LocalPort 8080
PS> (Get-NetTCPConnection -LocalPort 8080).OwningProcess

だけ覚えておけばなんとかなるかも。