この記事では、マクロから呼び出されたバッチファイルから複数の実行結果を個別に受け取る方法についてご説明します。
【動画】マクロから呼び出されたバッチファイルから複数の実行結果を個別に受け取る実際の動き
本題に入る前に、まずは次の動画をご覧ください。
まずはマクロからバッチファイルが呼び出されてバッチファイルが実行されます。
バッチファイルが実行されると、その実行結果をマクロ側が受け取って実行結果格納用の変数に格納されます。
次に、格納された実行結果を1行ずつ分割して配列に格納します。
配列に格納された配列から、何回目に実行されたコマンド結果なのか判定し、今回用意したテキストボックスに出力しています。
マクロ作成の流れ
今回は、実行されたコマンドの実行結果を、実行された何回目かごとに用意したテキストボックス(今回は3つ)にそれぞれ出力しています。
バッチファイルとExcelファイルの例
バッチファイル
今回は下のバッチファイルを用意しました。
@echo off echo (1)pingの実行1 ping 192.168.11.0 echo (2)pingの実行2 ping 192.168.11.1 echo (3)pingの実行3 ping 192.168.11.2
バッチファイルには、pingコマンドを実行するコードが3つ記述されています。
バッチファイルを実行すると以下の結果が表示されます。(指定したIPアドレスいずれも応答していない状態であることを知らせるメッセージが返ってきた)
Excelファイル
今回は下のExcelファイルを用意しました。
実行ボタンをクリックするとバッチファイルが実行されて、設置されたテキストボックスにバッチファイル(今回はpingコマンド)の実行結果が出力されます。
出力イメージは下のとおりです。
先ほどのバッチファイルで実行されたコマンドごとに、実行結果がそれぞれのテキストボックスに出力されています。
コードの例
Option Explicit Private Sub btn_exec_Click() Dim wsh As Object 'WshShellインスタンス用変数 Dim exec As Object 'バッチファイル実行用変数 Dim batchFilePath As String '呼び出すバッチファイルの格納先 Dim outputVal As String 'バッチファイルが実行した結果格納用変数 Dim AryLines As Variant '1行ごとに分割した実行結果を格納する配列 Dim cmdNumber As Integer 'どのコマンドの実行結果なのかを識別するための変数 Dim cnt As Integer 'カウンタ用変数 '各テキストボックスをクリアする TextBox1.Text = "" TextBox2.Text = "" TextBox3.Text = "" 'どのコマンドかを識別する変数を初期化する cmdNumber = 0 '呼び出すバッチファイルの格納先を取得する batchFilePath = ThisWorkbook.Path & "\0319.bat" 'WshShellオブジェクトからインスタンスを生成する Set wsh = CreateObject("WScript.Shell") 'バッチファイルを実行する Set exec = wsh.exec("cmd /c " & batchFilePath) 'バッチファイルで実行されたコマンドの実行結果すべてをテキストボックスに出力する outputVal = exec.StdOut.ReadAll '実行結果を1行ごとに分割してlinesに格納する AryLines = Split(outputVal, vbCrLf) '配列AryLinesの要素数分処理を繰り返すFor文 For cnt = LBound(AryLines) To UBound(AryLines) If InStr(AryLines(cnt), "(1)pingの実行1") > 0 Then '行に「(1)pingの実行1」の文字列が含まれている場合 '1つ目に実行されたコマンドを示す1の値を変数cmdNumberに格納する cmdNumber = 1 ElseIf InStr(AryLines(cnt), "(2)pingの実行2") > 0 Then '行に「(2)pingの実行2」の文字列が含まれている場合 '2つ目に実行されたコマンドを示す2の値を変数cmdNumberに格納する cmdNumber = 2 ElseIf InStr(AryLines(cnt), "(3)pingの実行3") > 0 Then '行に「(3)pingの実行3」の文字列が含まれている場合 '3つ目に実行されたコマンドを示す3の値を変数cmdNumberに格納する cmdNumber = 3 Else '行に「(1)pingの実行1」「(2)pingの実行2」「(3)pingの実行3」のいずれも含まれていない場合 Select Case cmdNumber Case 1 'cmdNumberが1の場合(1つ目に実行されたコマンドの実行結果) '1つ目に実行されたコマンドの実行結果をTextBox1に出力する TextBox1.Text = TextBox1.Text & AryLines(cnt) & vbCrLf Case 2 'cmdNumberが2の場合(2つ目に実行されたコマンドの実行結果) '2つ目に実行されたコマンドの実行結果をTextBox1に出力する TextBox2.Text = TextBox2.Text & AryLines(cnt) & vbCrLf Case 3 'cmdNumberが3の場合(3つ目に実行されたコマンドの実行結果) '1つ目に実行されたコマンドの実行結果をTextBox1に出力する TextBox3.Text = TextBox3.Text & AryLines(cnt) & vbCrLf End Select End If Next cnt End Sub
注目すべきコード①
最初に見て頂きたいのは25行目から28行目です。
'WshShellオブジェクトからインスタンスを生成する Set wsh = CreateObject("WScript.Shell") 'バッチファイルを実行する Set exec = wsh.exec("cmd /c " & batchFilePath)
コードの説明
以上のコードは、WshShellオブジェクト用インスタンスを生成してバッチファイルを実行する処理のコードです。
WshShellオブジェクトからインスタンスを生成したら、execメソッドでコマンドプロンプトを開き、コマンドプロンプト上で実行するバッチファイル(batchFilePath)を実行します。
実行し終わったら、コマンドプロンプトを閉じます。
「cmd」はコマンドプロンプトの実行ファイル「cmd.exe」を開くコマンドで、「/c」はコマンドを実行した後にコマンドプロンプトを閉じるようにするオプションです。
注目すべきコード②
次に見て頂きたいのは31行目から34行目です。
'バッチファイルで実行されたコマンドの実行結果すべてをテキストボックスに出力する outputVal = exec.StdOut.ReadAll '実行結果を1行ごとに分割してlinesに格納する AryLines = Split(outputVal, vbCrLf)
コードの説明
以上のコードは、バッチファイルで実行されたコマンドの実行結果すべてをテキストボックスに出力する処理のコードです。
StdOutプロパティからReadAllメソッドを呼び出し、バッチファイルの実行結果をすべて取得します。
今回は取得したバッチファイルの実行結果を個別に受け取ることが目的なので、一旦変数outputValに格納した後、格納された変数outputValの値を1行ずつ分割して配列AryLinesに格納します。
注目すべきコード③
次に見て頂きたいのは37行目です。
'配列AryLinesの要素数分処理を繰り返すFor文 For cnt = LBound(AryLines) To UBound(AryLines)
コードの説明
以上のコードは、配列AryLinesの要素数分処理を繰り返すFor文です。
取得したバッチファイルの実行結果の行数分処理を繰り返します。
注目すべきコード④
次に見て頂きたいのは39行目から58行目です。
If InStr(AryLines(cnt), "(1)pingの実行1") > 0 Then '行に「(1)pingの実行1」の文字列が含まれている場合 '1つ目に実行されたコマンドを示す1の値を変数cmdNumberに格納する cmdNumber = 1 ElseIf InStr(AryLines(cnt), "(2)pingの実行2") > 0 Then '行に「(2)pingの実行2」の文字列が含まれている場合 '2つ目に実行されたコマンドを示す2の値を変数cmdNumberに格納する cmdNumber = 2 ElseIf InStr(AryLines(cnt), "(3)pingの実行3") > 0 Then '行に「(3)pingの実行3」の文字列が含まれている場合 '3つ目に実行されたコマンドを示す3の値を変数cmdNumberに格納する cmdNumber = 3
コードの説明
以上のコードは、取得したバッチファイルの実行結果の中からどのコマンドの実行結果なのかを判定し、識別するための変数に値を設定する処理のコードです。
今回はバッチファイルで3つのコマンドを実行しています。
バッチファイルで記述されたコマンドを複数実行された場合に、マクロ側はそれぞれのコマンドが何番目に実行されたか特定することはできません。
そこで、それぞれのコマンドが何番目に実行されたかを特定するために、バッチファイル側で「何番目に実行されたコマンド」であることが分かるよう補足情報を追記しておきます。
その補足情報は下の赤枠の1文です。
以上の赤枠の情報をマクロ側が拾い、コマンドの実行情報が何番目に実行されたコマンドのものなのかを特定します。
「コマンドの実行情報が何番目に実行されたコマンドのものなのかを特定」するのが、39行目、46行目、53行目のIF文です。
1番目に実行されたコマンドの場合は43行目で、どのコマンドの実行結果なのかを識別するための変数cmdNumberに1を格納します。
2番目に実行されたコマンドの場合は51行目でcmdNumberに2を、3番目に実行されたコマンドの場合は58行目でcmdNumberに3を格納します。
なお、39行目、46行目、53行目のIF文の「(1)pingの実行1」「(2)pingの実行2」「(3)pingの実行3」の文字列はバッチファイル側と同じにする必要があるので、違いが無いよう気を付けてください。(IF文の条件に合致しない)
注目すべきコード⑤
次に見て頂きたいのは60行目から89行目です。
Else '行に「(1)pingの実行1」「(2)pingの実行2」「(3)pingの実行3」のいずれも含まれていない場合 Select Case cmdNumber Case 1 'cmdNumberが1の場合(1つ目に実行されたコマンドの実行結果) '1つ目に実行されたコマンドの実行結果をTextBox1に出力する TextBox1.Text = TextBox1.Text & AryLines(cnt) & vbCrLf Case 2 'cmdNumberが2の場合(2つ目に実行されたコマンドの実行結果) '2つ目に実行されたコマンドの実行結果をTextBox1に出力する TextBox2.Text = TextBox2.Text & AryLines(cnt) & vbCrLf Case 3 'cmdNumberが3の場合(3つ目に実行されたコマンドの実行結果) '1つ目に実行されたコマンドの実行結果をTextBox1に出力する TextBox3.Text = TextBox3.Text & AryLines(cnt) & vbCrLf End Select End If
コードの説明
以上のコードは、バッチファイルの実行結果の行に「(1)pingの実行1」「(2)pingの実行2」「(3)pingの実行3」の文字列のいずれも含まれていない場合に、コマンドごとにバッチファイルの実行結果をテキストボックスに出力するコードです。
cmdNumberの値が1の場合は71行目で1つ目に実行されたコマンドの実行結果をTextBox1(1つ目のコマンドの実行結果表示用)に出力します。
cmdNumberの値が2の場合は78行目で2つ目に実行されたコマンドの実行結果をTextBox2(2つ目のコマンドの実行結果表示用)に出力します。
cmdNumberの値が3の場合は85行目で3つ目に実行されたコマンドの実行結果をTextBox3(3つ目のコマンドの実行結果表示用)に出力します。
動作確認
「バッチファイルとExcelファイルの例」をご覧ください。
最後に
この記事では、マクロから呼び出されたバッチファイルから複数の実行結果を個別に受け取る方法についてご説明しました。
マクロから呼び出されたバッチファイルから複数の実行結果を個別に受け取りたい場合は本記事を参考にして頂けたら幸いです。
プログラミングのスキルを習得するなら
プログラミングのスキルを習得したい、今のスキルをもっと高めたい、そう考えているなら「プログラミングスクール」がおすすめです。
プログラミングのスキルの基礎を身につけるなら「TechAcademy」で1週間の無料体験があるので、これで「プログラミングの基礎」を学ぶのにおすすめですよ。