none
Invoke-Commandを使用した、戻り値の取得方法について RRS feed

  • 質問

  • nishigunと申します。
    未熟で申し訳ないですが、powershellのご質問をさせてください。

    ■環境
    端末:2台(端末A.端末Bとします)
    OS:Windows2008 Server(R2 spなし 2台とも)
    IP:端末A=192.168.1.2
    IP:端末B=192.168.1.1
    powershell: version:2.0
    ミドル:端末Aにジョブ管理ソフトManagerあり。端末Bにはミドルウェアなし

    ■ご質問

    端末Aに導入されているジョブ管理ソフトからpowershell.exeを呼出し、
    Invoke-Comanndで端末Bを経由して命令を実行するスクリプトを作成しようと思ってます。
    まず、端末Aから端末Bにリモートログインして、サービス名の数を取得して、
    問題なし⇒exit 0。問題あり⇒exit 255。
    見たいな事を実施しようと考えております。

    問題点として、
    スクリプトは作成できたのですが、端末B側のエラーコードを端末Aが取得できず困っております。
    過去ログを参照して真似てみたのですがうまくいきません。

    スクリプトは下記の通りです。
    ご存知であれば、どなたかご指導いただきたくおねがいいたします。

    ■端末Aのスクリプト
    [C:\PCA\PCA.ps1]
    ---------------------
    invoke-command -ComputerName 192.168.1.1 -ScriptBlock{invoke-command -filepath $args[0] -computername 192.168.1.1 ;$lastexitcode} -argumentlist C:\PCB\PCB.ps1
    ---------------------

    ■端末Bのスクリプト
    [C:\PCB\PCB.ps1]
    ---------------------
    #netstartでサービスを確認
    $CMD = net start | Select-String "AAA" | measure-object|%{$_.count}

    #サービス数をチェック
    if ($cmd -eq 3)
     {
      exit 0
     }  
    else
     { 
            exit 255
     }  
    ---------------------

    2013年2月6日 9:06

回答

  • 最終的にジョブ管理ソフトがpowershell.exeからの終了コードを受け取る必要があるということでしょうか。

    それであれば以下のようにするとどうでしょうか?

    ■端末Aのスクリプト

    [C:\PCA\PCA.ps1]
    ---------------------
    $exitcode = invoke-command -ComputerName 192.168.1.1 -ScriptBlock{invoke-command -filepath $args[0] } -argumentlist C:\PCB\PCB.ps1

    exit $exitcode

    ---------------------

    ■端末Bのスクリプト
    [C:\PCB\PCB.ps1]
    ---------------------
    先ほどのと同じ

    つまりは、まずPCA.ps1がリモートのPCB.ps1をキックし、その結果を$exitcodeに格納しています。

    そして$exitcodeをPCA.ps1の終了コードとしています。

    これでジョブ管理ソフトが直接呼び出すPCA.ps1が、終了コードを返すようになるかと思います。

    • 回答としてマーク nisigun 2013年2月7日 0:53
    2013年2月6日 11:29
    モデレータ

すべての返信

  • シェル変数$lastexitcodeは直前に実行したWin32ネイティブアプリの終了コードを格納する変数です。

    一方、Invoke-Command -FilePath PCB.ps1 -ComputerName 192.168.1.1 の意味するところは、192.168.1.1 に新しくPSセッション(この場合、同一コンピュータでの実行なのでループバックセッションとなる)を作成し、そこでPCB.ps1ファイルの中身を実行するということになります。

    したがって、PCB.ps1内で終了コードを返しても、それを実行したループバックセッションはスクリプトの終了と同時に消滅するので、$lastexitcodeの値も消滅しています。

    $lastexitcodeの値をどうしても呼び出し元から参照したいというのであれば別ですが、この場合、終了コードにこだわらずもっと簡単にしても良いのではないかと思います。

    スクリプトの構成自体は手を入れないで呼び出し方だけを変えるなら、

    ■端末Aのスクリプト
    [C:\PCA\PCA.ps1]
    ---------------------
    invoke-command -ComputerName 192.168.1.1 -ScriptBlock{invoke-command -filepath $args[0] } -argumentlist C:\PCB\PCB.ps1
    ---------------------

    ■端末Bのスクリプト
    [C:\PCB\PCB.ps1]
    ---------------------
    #netstartでサービスを確認
    $CMD = net start | Select-String "AAA" | measure-object|%{$_.count}

    #サービス数をチェック
    if ($cmd -eq 3)
     { 
      0
     }   
    else
     { 
     255
     }   
    ---------------------

    たとえばこのようなものでも十分なのではないでしょうか。


    2013年2月6日 9:53
    モデレータ
  • ご返信ありがとうございます。
    非常に参考になります。

    エラーパターン(255)で試した結果、ご指導いただいた結果が返ってきました。
    しかしジョブ管理ソフトで検証した結果、終了コード0で値が帰ってきました。

    どうやらご指摘の通り、$lastexitcodeの値が消えた事が原因のようです。
    ※ジョブ管理ソフトは32bitアプリケーションとサポート部署に伺った記憶があります。

    何らかの形で$lastexitcode残す方法はございませんでしょうか。

    経験不足で申し訳ありません。
    ヒントでも構いませんので
    お手数ですが、ご指導いただければ幸甚です。

    2013年2月6日 10:47
  • 最終的にジョブ管理ソフトがpowershell.exeからの終了コードを受け取る必要があるということでしょうか。

    それであれば以下のようにするとどうでしょうか?

    ■端末Aのスクリプト

    [C:\PCA\PCA.ps1]
    ---------------------
    $exitcode = invoke-command -ComputerName 192.168.1.1 -ScriptBlock{invoke-command -filepath $args[0] } -argumentlist C:\PCB\PCB.ps1

    exit $exitcode

    ---------------------

    ■端末Bのスクリプト
    [C:\PCB\PCB.ps1]
    ---------------------
    先ほどのと同じ

    つまりは、まずPCA.ps1がリモートのPCB.ps1をキックし、その結果を$exitcodeに格納しています。

    そして$exitcodeをPCA.ps1の終了コードとしています。

    これでジョブ管理ソフトが直接呼び出すPCA.ps1が、終了コードを返すようになるかと思います。

    • 回答としてマーク nisigun 2013年2月7日 0:53
    2013年2月6日 11:29
    モデレータ
  • 何度もご返信ありがとうございます。

    ご教示いただきました内容を実施した所、うまく戻り値を取得できました。

    まさか$exitcodeを変数とするとは・・その発想が浮かびませんでした。

    動作確認できましたので、これで大丈夫だと思います。

    お忙しい中、ご対応いただきありがとうございました。

    2013年2月7日 0:53