【C#】C#から複数渡された値を元に複数実行されたバッチファイルが返す複数の値をC#側が個別に受け取るには

この記事では、C#から複数渡された値を元に複数実行されたバッチファイルが返す複数の値をC#側が個別に受け取る方法についてご説明します。

【動画】C#から複数渡された値を元に複数実行されたバッチファイルが返す複数の値をC#側がまとめて受け取る実際の動き

本題に入る前に、まずは次の動画をご覧ください。


まずはC#からバッチファイルが呼び出されてバッチファイルが実行されます。

バッチファイルを呼び出す際、バッチファイル側に値を渡します。

今回はバッチファイル側に3つの値を渡しています。

バッチファイルが実行されると、C#側から渡された値を使って実行された結果をC#側が受け取って実行結果格納用の変数に格納されます。

次に、格納された実行結果を1行ずつ分割して配列に格納します。

配列に格納された配列から、何回目に実行されたコマンド結果なのか判定し、今回用意したテキストボックスに出力しています。

コードの流れ

STEP.1
バッチファイルを元にProcessStartInfoインスタンスを作成する
バッチファイルを元にProcessStartInfoインスタンスを作成します。
STEP.2
バッチファイルに値を渡し、バッチファイルを実行する
バッチファイルに値を渡し、バッチファイルを実行します。
今回はバッチファイル側に3つ値を渡します。
STEP.3
バッチファイルで実行されたコマンドの実行結果を取得する
バッチファイルで実行されたコマンドの実行結果を取得します。
STEP.4
STEP.3で取得した実行結果を1行ずつ分割し、配列に格納する
STEP.3で取得した実行結果を1行ずつ分割し、配列に格納します。
STEP.5
STEP.4の配列の値を1要素ずつ、何回目に実行されたコマンドの実行結果を判定する
STEP.4の配列の値を1要素ずつ、何回目に実行されたコマンドの実行結果を判定します。
今回は、実行されたコマンドの実行結果を、実行された何回目かごとに用意したテキストボックス(今回は3つ)にそれぞれ出力しています。

バッチファイルとフォームの例

バッチファイル

今回は下のバッチファイルを用意しました。

@echo off

rem pingの実行1
ping %1

rem pingの実行2
ping %2

rem pingの実行3
ping %3

バッチファイルには、pingコマンドを実行するコードが3つ記述されています。

このpingコマンドには、バッチファイルの引数が3つ使われており、pingコマンドそれぞれに「%1」「%2」「%3」の3つの引数が指定されています。

C#側から渡された値がそれぞれ「%1」「%2」「%3」に格納されます。

C#側から渡された値が渡された後に「%1」「%2」「%3」に格納されて、pingコマンドが実行されます。

フォーム

今回は下のフォームを用意しました。

実行ボタンをクリックするとバッチファイルが実行されて、設置されたテキストボックスにpingコマンドの実行結果が出力されます。

先ほどのバッチファイルで実行されたpingコマンドごとに、実行された結果がそれぞれのテキストボックスに出力されています。(指定したIPアドレスいずれも応答していない状態であることを知らせるメッセージが出力)

C#のコード(例)

App.configのコード

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>
    <appSettings> 

        <!-- バッチファイルのフルパス -->
        <add key="batFilePath" value="C:\work\10_勉強\21_C#\0061\0061.bat" />
    </appSettings>
</configuration>

注目すべきコード

見て頂きたいのは9行目です。

9行目は、バッチファイルのフルパスを「batFilePath」というキーに設定しているコードです。

「batFilePath」のキーの値をフォーム側のコードが参照して使います。

ちなみに、今回呼び出すバッチファイル「C:\work\10_勉強\21_C#\0061\0061.bat」は下の画像にあるバッチファイルです。

フォームのコード

using System;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using System.Configuration;

namespace wfcs_0061
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // App.configのappSettingsタグ内に記述した「batFilePath」のキーの値を取得して変数「batFilePath」に格納する
            string batFilePath = ConfigurationManager.AppSettings["batFilePath"];

            // バッチファイルに渡す引数を用意する(全部で3つ)
            string arg1 = "192.168.11.97";
            string arg2 = "192.168.11.98";
            string arg3 = "192.168.11.99";

            // 用意した引数(3つ)すべてを変数argumentsに格納する
            string arguments = $"{arg1} {arg2} {arg3}";

            // バッチファイルを元にProcessStartInfoインスタンスを生成する
            ProcessStartInfo psi = new ProcessStartInfo(batFilePath)
            {
                // バッチファイルのウィンドウを表示しないように設定する
                CreateNoWindow = true,

                // バッチファイルの出力結果を標準出力にリダイレクトするように設定する
                RedirectStandardOutput = true,

                // シェル機能を使用せずにプロセスを起動する
                UseShellExecute = false,

                // バッチファイルに渡す引数を設定する
                Arguments = arguments
            };

            // Processインスタンスを生成してバッチファイルを実行する
            Process proc = Process.Start(psi);

            // バッチファイルの実行結果を読み取るためのStreamReaderを生成する
            StreamReader reader = proc.StandardOutput;

            // 読み取ったバッチファイルの実行結果を1行ずつ格納する変数
            string line;

            // どのコマンドの実行結果なのかを識別するための変数を初期kする
            int cmdNumber = 0;

            // コマンドの実行結果の行数分処理を繰り返すループ
            // (コマンドの実行結果の最終行までデータを確認したらループを抜ける)
            while ((line = reader.ReadLine()) != null)
            {
                if (line.Contains("(1)pingの実行1"))
                {
                    // 行に「(1)pingの実行1」の文字列が含まれている場合

                    // 1つ目に実行されたコマンドを示す1の値を変数cmdNumberに格納する
                    cmdNumber = 1;
                }
                else if (line.Contains("(2)pingの実行2"))
                {
                    // 行に「(2)pingの実行2」の文字列が含まれている場合

                    // 2つ目に実行されたコマンドを示す2の値を変数cmdNumberに格納する
                    cmdNumber = 2;
                }
                else if (line.Contains("(3)pingの実行3"))
                {
                    // 行に「(3)pingの実行3」の文字列が含まれている場合

                    // 3つ目に実行されたコマンドを示す3の値を変数cmdNumberに格納する
                    cmdNumber = 3;
                }

                switch (cmdNumber)
                {
                    case 1:

                        // cmdNumberが1の場合(1つ目に実行されたコマンドの実行結果)

                        // 1つ目に実行されたコマンドの実行結果をTextBox1に出力する
                        textBox1.Text += line + Environment.NewLine;

                        // switchを抜ける
                        break;

                    case 2:

                        // cmdNumberが2の場合(2つ目に実行されたコマンドの実行結果)

                        // 2つ目に実行されたコマンドの実行結果をTextBox2に出力する
                        textBox2.Text += line + Environment.NewLine;

                        // switchを抜ける
                        break;

                    case 3:

                        // cmdNumberが3の場合(3つ目に実行されたコマンドの実行結果)

                        // 3つ目に実行されたコマンドの実行結果をTextBox3に出力する
                        textBox3.Text += line + Environment.NewLine;

                        // switchを抜ける
                        break;
                }
            }
        }
    }
}

注目すべきコード①

最初に見て頂きたいのは19行目です。

            // App.configのappSettingsタグ内に記述した「batFilePath」のキーの値を取得して変数「batFilePath」に格納する
            string batFilePath = ConfigurationManager.AppSettings["batFilePath"];

コードの説明

以上のコードは、App.configのappSettingsタグ内に記述した「batFilePath」のキーの値を取得して変数に格納するコードです。

「batFilePath」のキーの値は変数「batFilePath」に格納します。

注目すべきコード②

次に見て頂きたいのは27行目です。

            // バッチファイルに渡す引数を用意する(全部で3つ)
            string arg1 = "192.168.11.97";
            string arg2 = "192.168.11.98";
            string arg3 = "192.168.11.99";

            // 用意した引数(3つ)すべてを変数argumentsに格納する
            string arguments = $"{arg1} {arg2} {arg3}";

コードの説明

以上のコードは、バッチファイルに渡したい値(引数)を取得するコードです。

今回はバッチファイルに3つの値を渡したいので、22行目から24行目でバッチファイルに渡したい3つの値を取得し、27行目で変数argumentsに格納します。

なお、今回のようにバッチファイルに複数の値を渡したい場合は、渡したい値と次の渡したい値の間に半角スペースを挟んで結合させます。

今回はバッチファイル側に「192.168.11.97」「192.168.11.98」「192.168.11.99」の3つの値を渡します。

注目すべきコード③

次に見て頂きたいのは30行目から43行目です。

            // バッチファイルを元にProcessStartInfoインスタンスを生成する
            ProcessStartInfo processInfo = new ProcessStartInfo(batFilePath)
            {
                // バッチファイルのウィンドウを表示しないように設定する
                CreateNoWindow = true,

                // バッチファイルの出力結果を標準出力にリダイレクトするように設定する
                RedirectStandardOutput = true,

                // シェル機能を使用せずにプロセスを起動する
                UseShellExecute = false,

                // バッチファイルに渡す引数を設定する
                Arguments = arguments
            };

コードの説明

以上のコードは、バッチファイルを元にProcessStartInfoインスタンスを生成して、バッチファイルを実行する際の各情報を設定します。

コードの詳細

30行目のコードは、バッチファイルを元にProcessStartInfoインスタンスを生成します。

このインスタンスを生成することで、バッチファイルを実行したり、実行するバッチファイルの設定を色々と行うことができます。

33行目のコードでは、CreateNoWindowプロパティにtrueを設定しています。

CreateNoWindowプロパティにtrueを設定することで、バッチファイルのウィンドウが表示されなくなります。

36行目のコードでは、RedirectStandardOutputプロパティにtrueを設定しています。

RedirectStandardOutputプロパティにtrueを設定することで、バッチファイルの実行結果を直接読み取ることができるようになります。

39行目のコードでは、UseShellExecuteプロパティにfalseしています。

UseShellExecuteプロパティにfalseを設定することで、シェル経由で実行されず、バッチファイルの起動が直接実行されて高速化されます。(パフォーマンスの向上)

42行目のコードでは、Argumentsプロパティに値を設定することで、以下のイメージの通りにバッチファイル側の引数に値を渡すことができます。

今回は変数argumentsに「192.168.11.97」「192.168.11.98」「192.168.11.99」の3つの値を設定しているので、バッチファイル側の「%1」に「192.168.11.97」が、「%2」に「192.168.11.98」が、「%3」に「192.168.11.99」が渡されて、pingコマンドの引数としてpingコマンドが実行されます。

注目すべきコード④

次に見て頂きたいのは46行目から49行目です。

            // Processインスタンスを生成してバッチファイルを実行する
            Process proc = Process.Start(psi);

            // バッチファイルの実行結果を読み取るためのStreamReaderを生成する
            StreamReader reader = proc.StandardOutput;

コードの説明

以上のコードは、Processインスタンスを生成してバッチファイルを実行し、バッチファイルの実行結果を読み取るためのStreamReaderを生成する処理のコードです。

コードの詳細

46行目のコードでは、Processインスタンスを生成してバッチファイルを実行します。

49行目のコードでは、バッチファイルの実行結果を読み取るためのStreamReaderを生成します。

以上の処理により、バッチファイルの実行と実行結果の取得ができました。

注目すべきコード⑤

次に見て頂きたいのは59行目です。

            // コマンドの実行結果の行数分処理を繰り返すループ
            // (コマンドの実行結果の最終行までデータを確認したらループを抜ける)
            while ((line = reader.ReadLine()) != null)

コードの説明

以上のコードは、コマンドの実行結果の行数分処理を繰り返すwhile文です。

コマンドの実行結果の最終行までデータを確認したらwhileのループを抜けます。

注目すべきコード⑥

次に見て頂きたいのは61行目から81行目です。

                if (line.Contains("(1)pingの実行1"))
                {
                    // 行に「(1)pingの実行1」の文字列が含まれている場合

                    // 1つ目に実行されたコマンドを示す1の値を変数cmdNumberに格納する
                    cmdNumber = 1;
                }
                else if (line.Contains("(2)pingの実行2"))
                {
                    // 行に「(2)pingの実行2」の文字列が含まれている場合

                    // 2つ目に実行されたコマンドを示す2の値を変数cmdNumberに格納する
                    cmdNumber = 2;
                }
                else if (line.Contains("(3)pingの実行3"))
                {
                    // 行に「(3)pingの実行3」の文字列が含まれている場合

                    // 3つ目に実行されたコマンドを示す3の値を変数cmdNumberに格納する
                    cmdNumber = 3;
                }

コードの説明

以上のコードは、取得したバッチファイルの実行結果の中からどのコマンドの実行結果なのかを判定し、識別するための変数に値を設定する処理のコードです。

今回はバッチファイルで3つのコマンドを実行しています。

バッチファイルで記述されたコマンドを複数実行された場合に、C#側はそれぞれのコマンドが何番目に実行されたか特定することはできません。

そこで、それぞれのコマンドが何番目に実行されたかを特定するために、バッチファイル側で「何番目に実行されたコマンド」であることが分かるよう補足情報を追記しておきます。

その補足情報は下の赤枠の1文です。

以上の赤枠の情報をC#側が拾い、コマンドの実行情報が何番目に実行されたコマンドなのかを特定します。

「コマンドの実行情報が何番目に実行されたコマンドなのかを特定」するのが、61行目、68行目、75行目のIF文です。

1番目に実行されたコマンドの場合は61行目で、どのコマンドの実行結果なのかを識別するための変数cmdNumberに1を格納します。

2番目に実行されたコマンドの場合は68行目でcmdNumberに2を、3番目に実行されたコマンドの場合は75行目でcmdNumberに3を格納します。

なお、61行目、68行目、75行目のIF文の「(1)pingの実行1」「(2)pingの実行2」「(3)pingの実行3」の文字列はバッチファイル側と同じにする必要があるので、違いが無いよう気を付けてください。(IF文の条件に合致しない)

注目すべきコード⑦

次に見て頂きたいのは83行目から114行目です。

                switch (cmdNumber)
                {
                    case 1:

                        // cmdNumberが1の場合(1つ目に実行されたコマンドの実行結果)

                        // 1つ目に実行されたコマンドの実行結果をTextBox1に出力する
                        textBox1.Text += line + Environment.NewLine;

                        // switchを抜ける
                        break;

                    case 2:

                        // cmdNumberが2の場合(2つ目に実行されたコマンドの実行結果)

                        // 2つ目に実行されたコマンドの実行結果をTextBox2に出力する
                        textBox2.Text += line + Environment.NewLine;

                        // switchを抜ける
                        break;

                    case 3:

                        // cmdNumberが3の場合(3つ目に実行されたコマンドの実行結果)

                        // 3つ目に実行されたコマンドの実行結果をTextBox3に出力する
                        textBox3.Text += line + Environment.NewLine;

                        // switchを抜ける
                        break;
                }

コードの説明

以上のコードは、バッチファイルの実行結果の行に「(1)pingの実行1」「(2)pingの実行2」「(3)pingの実行3」の文字列のいずれも含まれていない場合に、コマンドごとにバッチファイルの実行結果をテキストボックスに出力するコードです。

cmdNumberの値が1の場合は90行目で1つ目に実行されたコマンドの実行結果をTextBox1(1つ目のコマンドの実行結果表示用)に出力します。

cmdNumberの値が2の場合は100行目で2つ目に実行されたコマンドの実行結果をTextBox2(2つ目のコマンドの実行結果表示用)に出力します。

cmdNumberの値が3の場合は110行目で3つ目に実行されたコマンドの実行結果をTextBox3(3つ目のコマンドの実行結果表示用)に出力します。

動作確認

バッチファイルとフォームの例」をご覧ください。

最後に

この記事では、C#から複数渡された値を元に複数実行されたバッチファイルが返す複数の値をC#側が個別に受け取る方法についてご説明しました。

C#から複数渡された値を元に複数実行されたバッチファイルが返す複数の値をC#側が個別に受け取りたい場合は本記事を参考にして頂けたら幸いです。

プログラミングのスキルを習得するなら

プログラミングのスキルを習得したい、今のスキルをもっと高めたい、そう考えているなら「プログラミングスクール」がおすすめです。

プログラミングのスキルの基礎を身につけるなら「TechAcademy」で1週間の無料体験があるので、これで「プログラミングの基礎」を学ぶのにおすすめですよ。

→ TechAcademyの「1週間 無料体験」はこちら