HOWTO · PowerShell
PowerShell スクリプトで特定の場所にジャンプする(goto の代替)
PowerShell に GOTO / goto はありません。関数へのジャンプ、if と switch による分岐、while と for による繰り返し、ラベル付き break / continue でネストしたループを抜ける方法を解説します。
このページの内容
PowerShell には goto コマンドがありません。cmd.exe のバッチファイルでは GOTO :label でラベル付きの行へ実行を送り、先へ飛ばしたり後ろへ戻したりできます。PowerShell はそのキーワードを意図的に持っていません。代わりに、名前付きの場所へは function を呼び出してジャンプし、経路の選択には if / elseif / else または switch、繰り返しには while や for、ネストしたループから抜けるにはラベル付きの break や continue を使います。
これらの制御構文は Windows PowerShell 5.1 でも PowerShell 7 でも同じです。以下の例は PowerShell 7.6.6 で確認しました。バッチから移るとき、メニューを作るとき、長い .ps1 をスパゲッティな GOTO なしで整理するときに使ってください。
関数で名前付きの場所へジャンプする
関数は、スクリプトの別の場所から呼び出せる名前付きブロックです。「このセクションへジャンプする」という用途に対する、PowerShell で最も安全な代替であり、バッチの CALL/ラベルサブルーチンや多くの GOTO 用途を置き換えます。スクリプトファイルでは、呼び出す前に関数を定義してください。
function Choice {
$continue = Read-Host "Do you want to continue?"
if ($continue -eq 'y') {
Write-Host "Welcome to PowerShell tutorials."
}
else {
Write-Host "Exited."
}
}
Choice
答えが y のときの出力:
Do you want to continue?: y
Welcome to PowerShell tutorials.
答えが y でないときの出力:
Do you want to continue?: n
Exited.
関数からだけ早めに抜けたいときは、return を使います。次の境界例では、負のコードに対して "invalid" を返し、それ以外は "ok:<n>" を返します。
function Get-Status {
param([int]$Code)
if ($Code -lt 0) {
return "invalid"
}
return "ok:$Code"
}
Get-Status -Code -1
Get-Status -Code 2
invalid
ok:2
return は現在の関数・スクリプト・スクリプトブロックを抜けます。呼び出し元やスケジューラ向けにプロセス終了コードを意図して設定したい場合以外は、exit より return を優先してください。再利用できる処理を関数にまとめておくと、スクリプト全体を走らせずにその一箇所だけ呼び出して後からテストしやすくなります。
if と switch で分岐する
条件文は、次にどの場所を実行するかを選びます。選択肢が少ないときは if / elseif / else の連鎖で足ります。メニュー風のナビには switch の方が分かりやすく、バッチの IF ... GOTO sectionA のあとに未使用セクションを飛ばす別の GOTO を置くパターンを置き換えます。
$action = Read-Host "Enter 1 for date marker or 2 for greeting"
switch ($action) {
'1' { Write-Output "DATE_MARKER" }
'2' { Write-Output "Hello, welcome to the PowerShell tutorial!" }
default { Write-Output "Invalid option selected." }
}
2 を選んだ場合:
Enter 1 for date marker or 2 for greeting: 2
Hello, welcome to the PowerShell tutorial!
無効な選択肢を選んだ場合:
Enter 1 for date marker or 2 for greeting: x
Invalid option selected.
各枝は完結したブロックなので、他のセクションを「飛ばす」ための二度目のジャンプは不要です。
while と for で繰り返す
ループは、:start のような開始ラベルへ飛び戻る構造化された代替です。while は条件が $true のあいだブロックを実行します。条件が最初から $false なら、PowerShell はそのブロックをスキップしてループの後へ進みます。制御されたスキップであり、任意ラベルへのジャンプではありません。
$a = 1
while ($a -lt 10) {
$a
$a++
}
1
2
3
4
5
6
7
8
9
境界例 — ループ本体は一度も実行されません:
$a = 10
Write-Output "before"
while ($a -lt 10) {
$a
$a++
}
Write-Output "after"
before
after
初期化・条件・増分をまとめて書きたいときは for ループが便利です。
for ($b = 1; $b -lt 6; $b++) {
Write-Host $b
}
1
2
3
4
5
PowerShell には、少なくとも一度は実行したい場合やコレクション走査向けに do/while、do/until、foreach もあります。いずれもバッチの GOTO :start ではなく、構造化されたループの考え方に従います。終了するまでメニューを出し続けたいときは、プロンプトと switch を while ($true) で包み、終了選択肢で break してください。
ラベル付き break と continue でネストしたループを抜ける
PowerShell のラベルは、バッチのジャンプ先ではありません。:outer のようなラベルは、ループや switch キーワードの直前に置けます。そのうえで break outer や continue outer — break/continue の行ではコロンを付けない — でその構文を対象にします。Microsoft は about_Break と about_Continue でこの形を文書化しています。PowerShell の構文として goto :Label や break :Label を示すページは誤りです。
:outer for ($i = 1; $i -le 3; $i++) {
for ($j = 1; $j -le 3; $j++) {
Write-Output "i=$i j=$j"
if ($j -eq 2) {
break outer
}
}
}
Write-Output "done"
i=1 j=1
i=1 j=2
done
$j が 2 のとき、break outer はラベル付きの外側ループ全体を抜け、Write-Output "done" から続行します。ラベルなしの break なら内側の for だけを抜けます。外側ループを終了するのではなく、外側の現在の反復の残りを飛ばして次の反復を始めたいときは continue outer を使います。
PowerShell の goto :label 文を発明したり、バッチ流の着地を期待して裸の :label を置いたりしないでください。また、ループ・switch・trap の外での break や continue も避けてください。PowerShell が呼び出しスタックをたどり、意図しない呼び出し元まで現在のランスペースを静かに終了させることがあります。
適切なジャンプ方法を選ぶ
| 目的 | 優先する手段 |
|---|---|
| 名前付きの再利用セクションを実行する | function + 呼び出し、必要なら return |
| 選択肢から選ぶ | if / elseif / else または switch |
| 繰り返す・戻る | while、for、do、または foreach |
| ネストしたループを早めに抜ける | ラベル付き break / continue |
| プロセス全体を終える | exit(慎重に) |
読みやすさを保ってください。多くの「ジャンプ」には関数と条件分岐を使い、繰り返しにはループ、ラベルはネストしたループ制御に取っておきます。性能が決め手になることはまれで、後からメンテするときは明快さと一本の出口の方が重要です。
FAQ
PowerShell に goto はありますか?
いいえ。cmd.exe のバッチと違い、PowerShell に goto キーワードはありません。公式の言語キーワードと PowerShell 言語仕様がフロー制御として挙げるのは break、continue、throw、return、exit であり、goto ではありません。
PowerShell のラベルは何をしますか?
ラベルはループや switch を印付けて、break / continue がその対象を選べるようにします。バッチの :label 行のような任意のジャンプ先にはなりません。
バッチの GOTO に対する日常的な最良の代替は?
名前付きの場所には関数を呼び出し、分岐と繰り返しには if / switch とループを使います。ネストしたループで外側を制御して抜けたいときだけ、ラベル付き break に手を伸ばしてください。
これらの技法は組み合わせられますか?
はい。メニュー用の関数では、しばしば while ループの中で switch を使い、入れ子の処理では外側ループを止める必要があるときにラベル付き break を足します。
これらの例は Windows PowerShell 5.1 でも動きますか?
ここで示した言語機能についてははい。検証した出力は PowerShell 7.6.6 で取得しています。Read-Host のホスト側プロンプト表示はホストによって少し違うことがあります。