質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PowerShell

Windows PowerShellはコマンドラインインターフェースであり、システム管理を含むWindowsタスク自動化のためのスクリプト言語です。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

Q&A

解決済

3回答

11251閲覧

PowerShellでループからうまく抜けられない

yontabaru

総合スコア19

PowerShell

Windows PowerShellはコマンドラインインターフェースであり、システム管理を含むWindowsタスク自動化のためのスクリプト言語です。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

0グッド

0クリップ

投稿2018/10/17 10:09

編集2018/10/18 01:00

前提・実現したいこと

PowerShellの質問です。教えてください。

メイン側のa.ps1から、b.ps1を呼びます。
呼ばれたb.ps1のループ処理で、3つのexeを実行するつもりが
例えば、2個目でエラーになったら、そこでループ処理を抜けて、
リターンコードに、エラーコードを入れて呼出し側a.ps1に値を返す

ということがしたいのですが、やはりループからうまく抜けられず、
breakと書くと、a.ps1にも戻らず終わってしまいます。

2個目でこけても、3個ともうまくいってもちゃんとリターンコードに値を入れて
呼出し側a.ps1に値を返すには、どのようにしたらいいのでしょうか。

該当のソースコード

【メイン側で以下のように呼び出す】 C:\temp\TestControl.ps1 echo "次のエラーコードで終了しましたーーーーーー>:$env:tmp_error_code" 【呼び出され側 TestControl.ps1】 $env:exe_error_code = 0 #初期化 # 指定したIF_IDに一致したデータを対象にする #---------------------------------------------------------- # csvの読込条件の設定 $csv_filter = { return ($_."IF_ID" -eq "$if_id") } #---------------------------------------------------------- #ファイル 読込 ループ Get-Content $InputFile | ConvertFrom-CSV | Where-Object $csv_filter | ForEach-Object { if ($_."IF_ID" -eq $global:if_id){ echo `n echo "ループして、処理を実行します。" echo `n $ifid = $_."IF_ID" $job = $_."DMXジョブ" $in_csv = $_."入力ファイル" $out_wk_table = $_."WK_出力テーブル" echo " IF_ID :$ifid" echo " DMXジョブ : $job" echo " 入力ファイル : $in_csv" echo " 出力ファイル : $out_wk_table" 実行コマンド.exe 2>> .\tmp_log.log echo "LASTEXITCODE : $LASTEXITCODE" } else{ echo "+++該当するIF_ID、存在しません。" } #終了コードからの処理振り分け switch($LASTEXITCODE){ 0{$level = "I" ;$msg = "正常終了" ;} 100{$level = "W" ;$msg = "警告終了" ;} 111{$level = "E" ;$msg = "異常終了" ;} #タスク自体が実行できなかった場合にデフォルト値を出力 default{$level = "F" ;$msg = "致命的な異常で終了";} } #終了コードの最大値保持 if(($env:exe_error_code -lt $LASTEXITCODE) -or(env:$exe_error_code -eq $null)){ $env:exe_error_code = $LASTEXITCODE } #後続処理の実行の有無判定 if($env:exe_error_code -ne 0){ echo "ジョブ実行は正常終了じゃなかった...."  ←リターンコードを break ←【ループ処理を抜けたいだけなのに、呼び出し側のメイン側に戻らず勝手に終了してしまう!!!】 【どうすれば、ループの処理でエラーが発生したら、ループだけを抜けられる??】 } } echo "-------------------LOOP 終了です!-----------------" # else{ if($env:exe_error_code -eq 0){ echo "全てのDMのジョブは正常終了でした!" echo "次の処理をを実行" } # } echo `n return($env:exe_error_code) ←【ここで、エラーでも正常でも、呼び出し側のメイン側に戻り値を返して、戻りたい!!!】``` ### サンプルデータ カテゴリ,IF_ID,実行ジョブ,入力ファイル,WK_出力テーブル,出力テーブル データ取込,IF_000010,Torikomim_Data_001.exe,001.csv,TB_001_wk,TB_001 データ取込,IF_000010,Torikomim_Data_002.exe,002.csv,TB_001_wk,TB_002 データ取込,IF_000010,Torikomim_Data_002.exe,002.csv,TB_001_wk,TB_003

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2018/10/17 10:21

いまのままではあまりに見にくいので、編集して<code>ボタン、’’’の枠の中にコードを貼り付けてください
guest

回答3

0

ベストアンサー

パイプラインではBreakは使わないほうがいいです。
パイプラインで処理するならば WhereSelect-Object -first 1の組み合わせが使えます。
ForEach{}内の結果がbool($true or $false)になるようにします。
サンプルを出します。

powershell

11..10 | foreach { 2 $exe_err = $_ -eq 8 3 4 if ($exe_err) 5 { 6 Write-Host "$_`でエラー起きたので中断します。" 7 $env:tmp_error_code = $_ 8 } 9 else 10 { 11 Write-Host "$_`は処理できました。" 12 $null = (5 + 1) 13 } 14 return $exe_err 15 16} | where {$_} | Select-Object -First 1 17 18Write-host "次のエラーコードで終了しましたーーーーーー>:$env:tmp_error_code"

実行してみてください。
どうでしょうか。

注意点ですがforeach {}の中ですがreturn $exe_errとしていますが
return書いてない場所の結果もパイプに流れてしまうのでforeach {}内の結果が帰ってくる処理は
最初に$null = を入れてください。
$null = (5 + 1)$null = を外すとどうなるか分かります。

--追記--
注意点

前回の回答で載せていますが
Select-Object -first 1はPowerShell V3以降でないと
ループから抜けてくれません。

投稿2018/10/18 01:58

編集2018/10/18 04:08
kamikazelight

総合スコア305

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yontabaru

2018/10/24 02:22

丁寧な説明、ありがとうございました。 おかげでうまく行きました!
guest

0

break の代わりに return を使うとか、ラベルを使ってみては?
制御構文

投稿2018/10/18 01:11

Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2018/10/18 01:12

return を使うというのは、そこで戻り値をセットしてそのスクリプトを終了し、呼び出し元に帰るという意味です。 ループを抜けるということではありません。
yontabaru

2018/10/24 02:25

Select-Object -first 1にすることで、回避策としました。 いろいろと教えていただいて、ありがとうございました。
yontabaru

2018/10/24 02:25

returnで、ちゃんと戻り値も取得できています! ありがとうございました。
guest

0

ForEach-Objectコマンドレットのループには、continue/breakステートメントは効きません。使用すると外側のfor/while/foreachステートメントのループに効くことになります。または、対応するループが無ければエラーになります。
質問の例では問題のbreakがメイン側のループを終わらせたのでしょう。
というわけで、for/while/foreachステートメントを使用する様に書き直して下さい。

投稿2018/10/17 12:25

編集2018/10/17 12:46
hichon

総合スコア5737

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yontabaru

2018/10/17 12:53 編集

ありがとうございます。 Get-Content $InputFile | ConvertFrom-CSV | Where-Object $csv_filter | ForEach-Object { の部分を Get-Content $InputFile | ConvertFrom-CSV | Where-Object $csv_filter { にして、括弧の中でwhileで、 $_."IF_ID" -eq $global:if_id の間、ループさせるイメージですか? while文にしたら、breakを使えば 問題なりますか? ちょっと実際、実行できないので こんなことまで聞いてしまってすみません
yontabaru

2018/10/18 01:03

ForEach-Objectを外して外のループ文を試してみましたが、 うまくループが回らなかったり・・・でうまく行きません。 すみませんが、教えてください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問