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

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

ただいまの
回答率

88.57%

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

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 4,865

yontabaru

score 19

 前提・実現したいこと

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  
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • y_waiwai

    2018/10/17 19:21

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

    キャンセル

回答 3

checkベストアンサー

+3

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

1..10 | foreach {
    $exe_err = $_ -eq 8

    if ($exe_err)
    {
        Write-Host "$_`でエラー起きたので中断します。"
        $env:tmp_error_code = $_
    }
    else
    {
        Write-Host "$_`は処理できました。"
        $null = (5 + 1)
    }
    return $exe_err

} | where {$_} | Select-Object -First 1

Write-host "次のエラーコードで終了しましたーーーーーー>:$env:tmp_error_code"


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

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

--追記--
注意点

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/24 11:22

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

    キャンセル

+1

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/17 21:52 編集

    ありがとうございます。

    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を使えば
    問題なりますか?

    ちょっと実際、実行できないので
    こんなことまで聞いてしまってすみません

    キャンセル

  • 2018/10/18 10:03

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

    すみませんが、教えてください。

    キャンセル

+1

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/18 10:12

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

    キャンセル

  • 2018/10/24 11:25

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

    キャンセル

  • 2018/10/24 11:25

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

    キャンセル

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

  • ただいまの回答率 88.57%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る