コマンドプロンプトの起動とコマンドの実行をWshShellクラスで行う
VBAでコマンドプロンプトの起動とコマンドの実行を行うには標準の機能だけでは実現できないため、WshShellクラスを利用します。
コマンドプロンプトの起動だけであればVBAのShell関数でも可能ですが、起動後はVBAから制御が離れてしまい、コマンド実行後の状態の確認が出来なくなります。
しかしWshShellクラスのExecメソッドを使えばコマンド実行後の動作状態の判定をVBAで行うことが出来ます。
なお、以下に紹介するコードでは事前にWshShellクラスを使うために参照設定を行っています。
事前設定
WshShellの参照設定は、VBA画面→ツールメニュー→参照設定で「Windows Script Host Object Model」を選択します。これでWshShellクラスを利用できるようになります。
WshShellはCreateObject関数を利用してこのような書き方を紹介されることが多いと思います。
1 2 |
Dim obj Set obj = CreateObject("WScript.Shell") |
しかしこの書き方では初めて使う方にとっては「言われた通りにしか書けない」という状況に陥りかねません。
そこで参照設定を行い、利用できるプロパティやメソッドを候補表示できるようにしています。
サンプルコード
以下のコードはコマンドプロンプトを起動してコマンドを実行し、そのコマンドの結果であるcmd.txtをCドライブ直下に出力するサンプルです。
実行するコマンドは以下になります。
1 2 3 4 5 |
SET DATE_TIME=%date% %time% C: cd C:\ echo %date% %time% >> cmd.txt dir /on >> cmd.txt |
コマンドを書く際にVBA特有の大事なことがあります。
通常のバッチファイルを手で実行する場合はバッチファイルが置いてあるディレクトリを基準に考えることが出来るためドライブやディレクトリの指定を書かないことが多いですが、VBAにコマンドを書いて実行する場合はバッチファイルが置いてあるわけではないため基準ディレクトリが存在しません。そのため、2行目のドライブ指定と3行目のディレクトリ指定がないと4行目のcmd.txtの出力先が未決定のため正しく動作しないため、必ずドライブとディレクトリの指定は書くようにしてください。
上記コマンドの内容は、ソースコードでは9行目から13行目の部分で配列に設定しています。この時点では文字列として配列に保持します。
16行目から22行目で配列に保持していたコマンド文字列を連結し、1つのコマンド文字列にしています。25行目でコマンドプロンプトの起動と変数に保持していたコマンド文字列の実行を行います。
その結果、コマンドに書いている通り、Cドライブ直下にcmd.txtを出力します。cmd.txtには実行日時とdirコマンドの結果が書き込まれます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
Sub CommandPronptExec() Dim sh As New IWshRuntimeLibrary.WshShell '// WshShellクラスオブジェクト Dim ex As WshExec '// Execメソッド戻り値 Dim sArCmd(4) '// 実行コマンド配列 Dim sCmd '// 実行コマンド Dim i '// ループカウンタ '// 実行する順にコマンドを配列に格納 sArCmd(0) = "SET DATE_TIME=%date% %time%" sArCmd(1) = "C:" sArCmd(2) = "cd C:\" sArCmd(3) = "echo %date% %time% >> cmd.txt" sArCmd(4) = "dir /on >> cmd.txt" '// コマンドを[ & ]で連結 For i = 0 To UBound(sArCmd) If (i > 0) Then sCmd = sCmd & " & " End If sCmd = sCmd & sArCmd(i) Next '// コマンド実行 Set ex = sh.Exec("cmd.exe /c " & sCmd) '// コマンド失敗時 If (ex.Status = WshFailed) Then '// 処理を抜ける Exit Sub End If '// コマンド実行中は待ち Do While (ex.Status = WshRunning) DoEvents Loop End Sub |
実行結果
C:\cmd.txtを開くと以下のように1行目に日時、2行目以降にdirコマンドの結果が出力されています。
複数のコマンドを実行したい場合
コマンドプロンプト実行後にコマンドを1行ずつ実行するために、名前を見ると使えそうなWshExec.StdIn.WriteLineメソッドを利用したいところですが、残念ながらエラーになります。
それでは複数のコマンドを実行したいときに困ります。実際にコマンドを実行する場合は1つのコマンドで終わることは少ないと思います。むしろ上のサンプルのように複数のコマンドを実行することの方が多いでしょう。
その場合は各コマンドを[ & ]で連結してExecメソッドでcmd.exeの起動と同時にコマンドも全て一度に実行するようにします。
コマンド自体があまりに多い場合は、VBAで全部書いてしまうと保守性が悪くなってしまうため、事前にバッチファイルを作成しておくか、または、VBAのファイル操作処理でバッチファイルの作成を行っておいて、それをShell関数やWshShell.Runメソッドで実行する方法を採用した方がよいでしょう。
バッチファイルの実行方法については「VBAでバッチファイル(bat)を実行する」をご参照ください。