HOWTO · PowerShell

Windows PowerShellでスクリプトを終了する方法

PowerShell で exit、return、throw、break、continue、Stop-Process を使い分け、適切なスコープを終了して終了コードを返す方法を解説します。

このページの内容

PowerShell スクリプトの「終了」には複数の意味があります。スクリプトのプロセス全体、現在の関数、ループの反復、別の OS プロセスのどれを止めるかによって、使用するステートメントが異なります。

目的 使用するもの
最上位スクリプトを終了して状態を返す exit <コード>
関数、スクリプト、またはスクリプトブロックを抜ける return
呼び出し元が捕捉できるエラーを通知する throw
ループまたは switch を抜ける break
次のループまたは switch の要素へ進む continue
別のローカルプロセスを終了する Stop-Process

exit で PowerShell スクリプトを終了する

exit はスクリプトまたは PowerShell インスタンスを終了します。省略可能な整数がプロセスの終了コードになります。慣例では 0 が成功、0 以外が失敗です。タスクスケジューラ、CI、ラッパープログラムが正しく判断できるように、各エラーコードの意味を文書化してください。

次のエントリースクリプトを Check-Config.ps1 として保存します。

param([Parameter(Mandatory)][string]$Path)

if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
    Write-Error "Configuration file not found: $Path"
    exit 2
}

Write-Output 'Configuration file found.'
exit 0

別の PowerShell セッションから子プロセスとして実行し、状態を確認します。

powershell.exe -NoProfile -File .\Check-Config.ps1 -Path .\missing.json
$LASTEXITCODE

最後のコマンドは 2 を表示します。PowerShell 7 では powershell.exe の代わりに pwsh を使用します。PowerShell の呼び出し元は $LASTEXITCODE から子プロセスの状態を取得でき、cmd.exe では %ERRORLEVEL% を使用します。

exit は最上位スクリプトの境界に限定するのが安全です。再利用する関数内で呼ぶと、対話セッション、テストランナー、または呼び出し元ホストまで閉じる可能性があります。関数はデータを返すかエラーをスローし、エントリースクリプトだけが結果を終了コードへ変換する構成にします。

return で現在のスコープを抜ける

return は現在の関数、スクリプト、またはスクリプトブロックを抜けます。それ自体がプロセスの終了コードを設定するわけではありません。

function Get-ConfigText {
    param([string]$Path)

    if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
        return $null
    }

    Get-Content -LiteralPath $Path -Raw
}

通常の PowerShell 関数では、return の後の式だけでなく、捕捉されていない成功ストリームの値がすべて出力になります。診断メッセージには余分な文字列を Write-Output で出すのではなく、Write-Verbose など適切なストリームを使用してください。

throw で捕捉可能なエラーを通知する

throw は既定でスクリプト終了エラーを生成し、catch ブロックまたは trap が処理するまで呼び出しスタックを巻き戻します。関数が有効な結果を返せず、回復方法を呼び出し元に判断させる場合に使用します。

function Get-RequiredConfig {
    param([string]$Path)

    if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
        throw "Configuration file not found: $Path"
    }

    Get-Content -LiteralPath $Path -Raw
}

try {
    $config = Get-RequiredConfig -Path '.\settings.json'
}
catch {
    Write-Error $_
    exit 2
}

このパターンでは責務が分かれます。関数は throw で失敗理由を伝え、エントリースクリプトが捕捉して公開する終了コードを決めます。すべての cmdlet エラーが自動的に catch へ届くわけではありません。非終了エラーをそこで処理する必要がある場合は -ErrorAction Stop を指定します。

breakcontinue は制御ブロック内だけで使う

break は最も近いループまたは switch を終了します。continue は現在の反復の残りを飛ばして次へ進みます。

foreach ($name in 'alpha', '', 'beta', 'stop', 'omega') {
    if ([string]::IsNullOrWhiteSpace($name)) {
        continue
    }
    if ($name -eq 'stop') {
        break
    }
    Write-Output $name
}

出力:

alpha
beta

これらは汎用のスクリプト終了コマンドではありません。ループ、switchtrap の外で使うと、PowerShell は呼び出しスタック上の制御構造を探し、見つからなければ現在のランスペースを終了することがあります。

Stop-Process で別のプロセスを終了する

Stop-Process はローカルコンピューター上の別プロセスを対象とし、現在のスクリプトを終了するものではありません。広い条件を使う前に -WhatIf で対象を確認します。

Get-Process -Name notepad -ErrorAction SilentlyContinue |
    Stop-Process -WhatIf

対象を確認してから -WhatIf を外してください。同じ名前のプロセスが複数ある場合は、既知のプロセスオブジェクトまたは PID を優先します。別ユーザーが所有するプロセスの停止には、管理者権限の PowerShell セッションが必要な場合もあります。

ネイティブプログラムの終了コードを保持する

$? は直前の PowerShell コマンドが成功したかを示します。一方、$LASTEXITCODE は直前のネイティブプログラムの終了コードを保持します。次のネイティブコマンドで上書きされるため、すぐに保存してください。

git status --porcelain
$gitCode = $LASTEXITCODE

if ($gitCode -ne 0) {
    Write-Error "git failed with exit code $gitCode"
    exit $gitCode
}

再利用するロジックでは return または throw を使い、exit <コード> は最上位スクリプトに限定します。これにより、関数の出力、制御フロー、OS のプロセス状態を混同せずに扱えます。

クリーンアップを保持し、キャンセルと区別する

クリーンアップは、処理を止める可能性がある行の後ではなく finally に置きます。PowerShell の言語キーワードのドキュメントによれば、finallytry が成功した場合、エラーが catch に届いた場合、exit が呼ばれた場合、または Ctrl+C がスクリプトを中断した場合にも実行されます。そのため、ストリーム、ロック、一時ファイルを解放する場所として適しています。

$stream = $null

try {
    $stream = [System.IO.File]::OpenRead($Path)
    # Process the stream.
}
finally {
    if ($null -ne $stream) {
        $stream.Dispose()
    }
}

再利用するコードは、途中で exit を呼ぶのではなく、エントリースクリプトへ throw または return します。これにより、クリーンアップ、診断、終了状態を一か所で決められます。Ctrl+C、停止されたジョブ、無効な入力は別のイベントです。それぞれをキャンセル、検証失敗、または呼び出し元・スケジューラが処理すべき別の状態のどれにするかを決め、文書化してください。これらを黙って一般的な失敗へまとめないでください。別プロセスを止めることはさらに別であり、通常の終了手段を優先します。Stop-Process -Force がファイルや状態のクリーンアップを妨げる影響を理解した場合だけ使用してください。

子スクリプトとホストを意図したスコープに保つ

呼び出し演算子は子スクリプトを独自のスクリプトスコープで実行します。ドットソーシングは現在のスコープで実行し、関数と変数を取り込みます。定義の取り込みが目的の場合にだけ使用します。

# Run the child in its own script scope.
& .\Child.ps1

# Import definitions into the current scope.
. .\Functions.ps1

再利用コードの exitreturn より強く、対話セッション、テストランナー、別のホストを閉じることがあります。powershell.exe -File または pwsh -File で開始した子プロセスは呼び出し元へ制御を返しますが、対話コンソールは現在のセッションを閉じることがあります。埋め込み Runspace やエディターは異なる場合があります。-File-Command、プロファイル、引用符、出力、終了状態を含め、実運用のコマンドラインを個別に確認してください。

推奨事項

最上位スクリプトの終了には exit <コード>、現在のスコープを抜けるには return、呼び出し元が扱える失敗には throw を使います。breakcontinue は対象のループまたは switch 内だけで使用し、Stop-Process は別のローカルプロセスに限定します。データを返すかエラーを送出する関数は再利用しやすく、小さなエントリースクリプトがシェル、スケジューラ、CI、ラッパー向けの安定した終了状態へ変換できます。