PowerShellのStop-Processで自分自身が止まる。exit 255で後続が消えた原因と直し方
裏で動いている古いスクリプトを1つ止めたくて、部下役のAI(Claude Code)がこの1行を流しました。
powershell -NoProfile -Command "Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -like '*_run_build_retry*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force; 'stopped ' + $_.ProcessId }"
返ってきたのは、次の3行だけです。
Exit code 255
stopped 21184
stopped 9072
同じコマンドの後ろには、スクリプトの書き直しと再起動を続けて書いていました。
そのどちらも走っていません。
探していた語が、探している側の命令の中にも入っていたからです。
止めたかったのは、切り離した1本だけだった
2026年10月10日の朝6時44分のことです。
部下役のAIは、声の生成を続けるPowerShellのスクリプトを、Start-Process で切り離して走らせていました。Start-Process は、新しいプロセス(動いているプログラムの単位)を起動する命令です。
スクリプトを直したので、古い実行を止めてから起動し直すつもりでした。
止める相手は、コマンドライン(起動したときの命令の文字列)で探しました。Get-CimInstance Win32_Process は、動いているプロセスの一覧を、起動時の命令つきで取り出す命令です。
その中から、スクリプト名の _run_build_retry を含むものを -like で拾い、Stop-Process で止める形でした。
CommandLineには、探している自分の命令も入っている
公式の説明では、Win32_Process の CommandLine は、そのプロセスを開始するために使われたコマンドラインです。
部下役のAIは、Bash(文字で命令を打つ画面の一種)から powershell -Command "…" の形でこの検索を動かしていました。
すると、検索している powershell.exe 自身の CommandLine に、検索語がそのまま入ります。
呼び出し元の bash.exe のコマンドラインにも、同じ文字列が丸ごと入っていました。
-like '*_run_build_retry*' は、自分にも、呼び出し元にも当たります。
4分後に一覧だけを出してみると、bash.exe が3つ、powershell.exe が1つ当たっていました。Stop-Process は、当たったものを順に止めていきます。
呼び出し元のシェルが止まれば、同じコマンドの後ろに書いた処理は、もう動きません。
画面に後から打った命令は、プロセスを開始したときのコマンドラインには入らないはずです。
この形にはまるのは、別のプログラムから powershell -Command で動かすときだと見ています。
Bash、cmd、タスクスケジューラ、AIの道具などから呼ぶ場合です。
画面に直接打った場合は、試していません。
11月13日に、ダミーで同じ形を作った
記事にするにあたり、止めても困らないダミーで再現しました。Start-Sleep 300; # psstopdemo_target を実行するだけのPowerShellを、隠して起動します。
そのうえで、Bash から一覧だけを出しました。
22480 bash.exe parent=6932 self=False
8684 bash.exe parent=22480 self=False
21644 powershell.exe parent=14464 self=False
24140 bash.exe parent=8684 self=False
2888 powershell.exe parent=24140 self=True
止めたいダミーは、3行目の21644だけです。
ほかの4つは、検索している自分と、それを呼んだBashでした。
parent は、そのプロセスを起動した親のプロセスの番号です。
同じ条件で Stop-Process まで流すと、ダミーと bash.exe を1つずつ止めたところで、Exit code 255 で終わりました。
後ろに書いた echo は出ていません。
10月10日と同じ止まり方です。
255という数字についても確かめました。Stop-Process -Id $PID -Force で自分を止めてみました。
PowerShellから見ると、$LASTEXITCODE は -1 でした。
このとき道具の表示は Exit code 255 です。
-1を0から255の範囲で表すと255になるので、その値が出ていると見ています。
公式の説明でも、Stop-Process は .NET の Kill メソッドで実装されているとあります。
直し方1:検索語を文字列の連結で作る
10月10日は、検索語を2つに割ってつなぐ形に直しました。
$pat = '*-File*_run_build_' + 'retry.ps1*'
Get-CimInstance Win32_Process |
Where-Object { $_.Name -eq 'powershell.exe' -and $_.CommandLine -like $pat } |
ForEach-Object { Stop-Process -Id $_.ProcessId -Force; 'killed ' + $_.ProcessId }
コマンドラインに残るのは '_run_build_' + 'retry.ps1*' で、つないだ後の文字列は現れません。
だから自分には当たらない、という考え方です。
6時49分と6時50分にこの形で流すと、どちらも後ろの書き直しと再起動まで最後まで走りました。
ただ、連結だけでは足りない場合があります。
11月13日の再現で、ダミーの起動と連結版の検索を、同じBashのコマンドに並べて書いてみました。
するとまた Exit code 255 です。
前半に書いたダミーの起動の部分に、検索語がそのまま入っていたためでした。
呼び出し元のコマンドラインは、1回に流したコマンドの全部です。
10月10日の版が無事だったのは、$_.Name -eq 'powershell.exe' でも絞っていたからでした。
6時50分のコマンドには、再起動のためにスクリプトの名前をそのまま書いていました。
名前で絞っていなければ、ここで呼び出し元のBashに当たっていたはずです。
直し方2:名前で絞って、$PIDを除く
$PID は、いま動いているPowerShell自身のプロセス番号が入る自動変数です。
英語圏のQ&Aでは、$_.ProcessId -ne $PID で自分を除く方法が紹介されています。
11月13日に、組み合わせを変えて試しました。
- そのまま:ダミーと bash.exe を止めて Exit code 255
- $PID だけ除く:ダミーと bash.exe を止めて Exit code 255
- 名前だけで絞る:ダミーを止めたあと自分も止まり、Bashから見た終了コードは127
- 名前で絞り、$PID も除く:ダミーだけを止め、終了コード0で後ろも実行
$PID で除けるのは、自分のPowerShellだけです。
呼び出し元のBashは名前で外さないと、自分ごと止まります。
いま僕が使っている形はこれです。
Get-CimInstance Win32_Process -Filter "Name='powershell.exe'" |
Where-Object { $_.CommandLine -like '*myjob.ps1*' -and $_.ProcessId -ne $PID } |
ForEach-Object { Stop-Process -Id $_.ProcessId -Force; 'stopped ' + $_.ProcessId }
myjob.ps1 のところを、止めたいスクリプトの名前に替えて使います。
PowerShell 7 で動かしている相手なら、名前は pwsh.exe です。-Filter の中で LIKE を使って絞る場合は、書き方が変わる点に気をつけてください。
公式の説明では、ワイルドカードは * ではなく % で、_ も任意の1文字を表します。
スクリプト名の _ が、別の文字にも当たることになります。
止める前に、一覧だけ出す
止める命令は、先に一覧だけで確かめると安全です。
Get-CimInstance Win32_Process |
Where-Object { $_.CommandLine -like '*myjob.ps1*' } |
ForEach-Object { '{0} {1} parent={2} self={3}' -f $_.ProcessId, $_.Name, $_.ParentProcessId, ($_.ProcessId -eq $PID) }
self=True の行があれば、そのまま止めると自分が止まります。
bash.exe や cmd.exe が並んでいれば、呼び出し元も当たっています。
公式の説明にも、プロセスを止めると、それに頼るほかのプロセスまで止まりうると書かれています。
Claude Code の PowerShell の道具から同じ一覧を出したときは、当たったのはダミーだけでした。
道具や呼び方によって、自分が当たるかどうかが変わるということです。
迷ったら、一覧の self と parent を見てから止めています。
参考
- 運営記録 2026-10-10:古い実行を止める1行が Exit code 255・連結と名前の絞り込みで直した
- 運営記録 2026-11-13:ダミーのプロセスでの再現と、組み合わせの比べ試し
- Win32_Process クラス(日本語版、2026年11月13日確認):https://learn.microsoft.com/ja-jp/windows/win32/cimwin32prov/win32-process
- Stop-Process(PowerShell 5.1・日本語版、2026年11月13日確認):https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.management/stop-process?view=powershell-5.1
- about_Automatic_Variables の $PID(PowerShell 5.1・日本語版、2026年11月13日確認):https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_automatic_variables?view=powershell-5.1
- WQL の LIKE 演算子(日本語版、2026年11月13日確認):https://learn.microsoft.com/ja-jp/windows/win32/wmisdk/like-operator
6時49分に起動し直したスクリプトは、まだ区切りの行をログに書けていませんでした。
原因は文字コードで、6時50分に先頭へBOMを付けて直しています。
Claude Codeが書いた.ps1が文字化けして動かない(PowerShell 5.1)。先頭にBOMを付けたら直った
切り離したPowerShellでは、OneDriveの中のファイルを消せない日もありました。
OneDrive配下でPowerShellの削除・移動が「アクセスが拒否されました」で止まる。Pythonで移して直した