第5回 WshShellオブジェクトの詳細(1):Windows管理者のためのWindows Script Host入門(3/4 ページ)
WshShellオブジェクトを利用し、スクリプトから外部プログラムを起動して、キー・ストロークを送信して制御する。
Execメソッドの使い方
FCのようなコマンドライン・ツールを実行する場合には、Execメソッドを利用する方法もある。Execメソッドも、パラメータとして実行するプログラムを指定する点ではRunメソッドと違いはない。しかし前述したとおり、Execメソッドを利用すれば、終了コードの取得だけでなく、標準入出力を通してコマンドにオプションを与えたり、コマンド実行の結果を取得したりできるようになる。
またExecメソッドは、戻り値としてWshScriptExecオブジェクトを返す。前述したクラス構成図から分かるとおり、WshScriptExecオブジェクトにはStatus、StdIn、StdOut、StdErr、ExitCode、ProcessIDの6つのプロパティがある。
メソッド/プロパティ | 内容 |
---|---|
Terminateメソッド | 開始したプロセスを終了するようにスクリプト・エンジンに指示する |
ExitCodeプロパティ | 実行したスクリプトまたはプログラムが設定した終了コードを返す |
ProcessIDプロパティ | WshScriptExecオブジェクトによって起動されたプロセスのプロセスID(PID) |
Statusプロパティ | 実行したスクリプトのステータス情報を返す |
StdInプロパティ | Execオブジェクトのstdin入力ストリーム |
StdOutプロパティ | Execオブジェクトの書き込み専用stdout出力ストリーム |
StdErrプロパティ | Execオブジェクトのstderr出力ストリーム |
WshScriptExecオブジェクトの内容 |
Statusは、起動したプログラムが実行中であれば0を、実行が完了していれば1を返す。StdIn、StdOut、StdErrは、起動したプログラムの標準入力、標準出力、標準エラー出力を読み書きするためのストリームを提供する。ExitCodeとProcessIDは、それぞれ終了コードとプロセスIDを返す。プログラムがまだ終了していない場合には、ExitCodeプロパティは0になっている。プロセスIDは、後述のAppActivateメソッド(プログラムをアクティブにする)で利用する。
WshScriptExecオブジェクトのTerminateメソッドを使えば、起動したプログラムを強制終了することができる(ただし、作業中のプログラムを強制終了するとデータが破損する可能性があるので、Terminateメソッドの利用はあまり推奨されない)。
ここで注意が必要なのは、WshScriptExecオブジェクトで扱う標準入出力は、Execメソッドで起動したプログラムから見た標準入出力なので、スクリプト側から見ると逆になってしまうことだ。つまりスクリプトから見ると、データを渡すのが標準入力になり、データを受け取るのが標準出力と標準エラー出力になる。WScriptオブジェクトの場合とは使えるメソッドとプロパティが逆になるので注意が必要だ。この関係を図にすると次のようになる。
WshScriptExecオブジェクトの標準入出力
WshScriptExecオブジェクトを利用すれば、起動したプログラムの標準入出力を使ってデータをやりとりできる。しかしWshScriptExecオブジェクトのStdIn/StdOut/StdErrはいずれも起動したプログラムから見たものなので、感覚的には逆になることに注意が必要。
それでは、Execメソッドを用いて先のFCコマンドを利用してファイルを比較するスクリプトを書き換えてみよう。これは次のようになる。
1: Set objShell = WScript.CreateObject("WScript.Shell")
2: Set objExec = objShell.Exec("fc.exe test.txt test2.txt")
3:
4: Do While objExec.Status = 0
5: WScript.Sleep 100
6: Loop
7:
8: fcresult = objExec.ExitCode
9: If fcresult = 0 Then
10: WScript.Echo "test.txtとtest2.txtは同じ内容のファイルです"
11: ElseIf fcresult = 1 Then
12: WScript.Echo "test.txtとtest2.txtは異なる内容のファイルです"
13: Else
14: WScript.Echo "FC が結果 " & fcresult & " を返しました"
15: End If
Execメソッドを利用する場合には、起動したプログラムの終了を待つというオプションは指定できないので、明示的にループを回すことでプログラムの終了を待っている(4〜6行目)。プログラムの実行が終了すればStatusが0でなくなるので、その場合はループを脱出してExitCodeの値を調べる(単純な無限ループにしてしまうと処理が重くなるので、終了判定を1回終了するごとに100msecのスリープを実行している)。
このように、直前に起動したプログラムの終了を待ってから次のプログラムを実行するようなスクリプトなら、Runメソッドを利用した方が簡単である。ただしExecメソッドを利用している場合、コマンドライン・プログラムの実行時に新しいウィンドウを表示しないので、1つのコマンド・プロンプトの中ですべての処理を完結させられるというメリットがある。
Execメソッドでの標準入出力の利用
すでに述べたとおり、Execメソッドで最も強力な点は、起動したプログラムの標準入出力を利用できることである。WshScriptExecオブジェクトのStdIn、StdOut、StdErrはTextStreamオブジェクトであり、WScriptオブジェクトのStdIn、StdOut、StdErrプロパティと同じように扱うことができる(WScriptオブジェクトの標準入出力操作メソッドについては連載第3回を参照)。ただし、上でも述べたとおり、WScriptオブジェクトの場合とは使えるメソッド・プロパティが逆になる点に注意する。
ここでWshScriptExecオブジェクトの標準出力を使う例として、ipconfigコマンドを利用して、スクリプトを実行したコンピュータ自身のIPアドレスを取得してみよう。ipconfigコマンドを実行すると標準出力に以下のような出力が表示される。
D:\WSH>ipconfig
Windows IP Configuration
Ethernet adapter ローカル エリア接続 2:
Connection-specific DNS Suffix . : d-advantage.com
IP Address. . . . . . . . . . . . : 192.168.0.121
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 192.168.0.56
D:\WSH>
このうち、自分のIPアドレスは「IP Address」と書かれた行の「:」以降なので、スクリプトによってこの部分を切り出すことを考える。文字列の中にキーワードが含まれるかどうかや、特定の文字が何文字目に存在するかは、VBScriptのInStr関数を利用することで取得できる。文字列の一部分を切り出すにはMid関数を用いる。コードは次のようになる。
1: Set objShell = WScript.CreateObject("WScript.Shell")
2: Set objExec = objShell.Exec("ipconfig.exe")
3:
4: Do Until objExec.StdOut.AtEndOfStream ' 標準出力が終了するまでループ
5: strLine = objExec.StdOut.ReadLine ' 1行読み込み
6: If InStr(strLine, "IP Address") <> 0 Then ' "IP Address" が含まれているか?
7: iColon = Instr(strLine, ":") ' ":" の位置を調べる
8: strAddress = Mid(strLine, iColon + 2) ' アドレス部分の切り出し
9: Wscript.Echo strAddress ' 出力
10: End If
11: Loop
起動プログラムからの標準出力を処理する場合には、StdOutストリームの終端までを処理すれば、Statusプロパティを意識することなく、実行が終了するまでの結果を読み込むことができる。また、ReadLineメソッドはストリームにデータがなければデータが追加されるまで待つので、先ほどのようにSleepで明示的に待つ必要はなくなる。このように、Execメソッドを利用すれば、起動したプログラムの標準出力を扱うスクリプトを非常にすっきりと書ける。
4行目でストリームの終端までループし、5行目で1行読み込んでstrLine変数に代入する。6行目で“IP Address”"というキーワードがその行に含まれるかどうかを調べ、含まれていればInStr関数が0以外の値を返すので、7〜9行目を実行する。7行目では「:」の位置を調べてiColon変数に代入する。ここでは“IP Address”を含む行には必ず「:」が含まれていると仮定して0かどうかの判定は省略しているが、より安全なスクリプトとするためには、その判定も追加すべきである。8行目ではMid関数を使ってコロンの先にあるIPアドレスの文字列をstrAddressに代入する。「+2」とあるのは、iColonの位置には「:」という文字があり、次の位置にはスペースがあるため、IPアドレスの始まる部分はiColonの2文字先であることを示している。9行目で得られたアドレスを出力する。実行すると次のようになる。
D:\WSH>cscript ipaddr.vbs
192.168.0.121
D:\WSH>
Copyright© Digital Advantage Corp. All Rights Reserved.