VBAで「何かを実行したい」と考えたとき、真っ先に候補に上がるのが Application.Run です。
一方で、外部プログラムやバッチ、PowerShell、別アプリを起動したい場面では WScript.Shell の Run が登場します。
ただ、実務ではここで混乱が起きます。
- 「Run」という名前が同じで、同じものに見える
- どこまでが“VBAの世界”で、どこからが“Windowsの世界”なのかが曖昧
- エラー処理・待機・引数・セキュリティで後から詰まる
この記事では、Application.Run と WScript.Shell Run が“何を実行するものか”を切り分け、実務で迷わない判断軸と実装パターンを整理します。
目次
- ✅ まず結論:2つのRunは「実行対象の世界」が違う
- ・Application.Run
- ・WScript.Shell.Run
- ✅ 使い分けの判断フロー(実務で迷わない軸)
- ✅ Application.Runの特徴と実務の落とし穴
- ・何が得意か
- ・実務での落とし穴
- ・“動けばOK”になりがちな悪い例
- ✅ WScript.Shell.Runの特徴と実務の落とし穴
- ・何が得意か
- ・実務での落とし穴
- ✅ 実務で壊れない実装パターン(設計意図つき)
- ✅ 1) Application.Runを安全に使うラッパー
- ✅ 2) WScript.Shell.Runを安全に使うラッパー(待機・引用符・終了コード)
- ✅ 具体例:それぞれ「何を実行するか」を見える化
- ・Application.Run:別ブックのマクロを実行
- ・WScript.Shell.Run:バッチファイルを実行(待機する)
- ✅ どちらを選んでも「実務で詰まらない」ためのチェックリスト
- ✅ まとめ:Application.RunとWScript.Shell Runは「世界が違う」
✅ まず結論:2つのRunは「実行対象の世界」が違う
・Application.Run
- Excel(VBA)の中で、VBAプロシージャ(マクロ)を実行する
- 対象は「標準モジュールの Sub/Function」「アドインのマクロ」「別ブックのマクロ」など
- つまり VBAの実行器
・WScript.Shell.Run
- Windows(OS)の中で、外部コマンドやアプリを実行する
- 対象は「exe」「bat」「cmd」「powershell」「既定アプリでファイルを開く」など
- つまり OSコマンド実行器
ここを誤解したまま進むと、
「Application.Runでbatを呼べるのでは?」
「Shell.RunでVBAマクロを呼べるのでは?」
のような“すれ違い”が起きます。
✅ 使い分けの判断フロー(実務で迷わない軸)
次の質問に答えるだけで決まります。
- 実行したいのは VBAマクロ?
→ はい:Application.Run
→ いいえ:次へ - 実行したいのは Windowsの外部プログラム?(bat/cmd/exe/powershell等)
→ はい:WScript.Shell.Run
→ いいえ:次へ - 実行後にExcel側は 待つ必要がある?
→ 待つ:WScript.Shell.Run のbWaitOnReturn=Trueを検討
→ 待たない:Falseで非同期
このフローを記事の冒頭に置いておくと、読者は迷いません。
✅ Application.Runの特徴と実務の落とし穴
・何が得意か
- マクロ名(文字列)で実行できる
- 引数付きで呼べる(※呼び出し側がVariantで渡せる)
- 「どのブックのマクロか」を意識して呼び分けできる
・実務での落とし穴
- マクロ名を文字列で持つと、リネームに弱い(保守性低下)
- 参照しているブック(ThisWorkbook/ActiveWorkbook)のズレで想定外を実行
- ブックが閉じた/開いていないと呼べない(別ブックマクロ)
・“動けばOK”になりがちな悪い例
- どのブックの何を呼ぶか曖昧
- マクロ名のハードコード
- エラー時に何が起きたか分からない
✅ WScript.Shell.Runの特徴と実務の落とし穴
・何が得意か
- bat/cmd/exe/powershell など外部を起動できる
- 引数(コマンドライン)を組める
- 同期/非同期(待機)の選択ができる
・実務での落とし穴
- パスにスペースがあると失敗(引用符の付け忘れ)
- 実行環境(権限・パス・ポリシー)に依存
- 何が失敗したかが分かりにくい(exit codeの扱い)
✅ 実務で壊れない実装パターン(設計意図つき)
ここからは、「再利用できる形」にすることを優先して、共通化したサンプルを提示します。
ポイントは3つです。
- 「実行」を1か所に集約して、呼び出し側を薄くする(変更に強くする)
- 失敗時に“何を実行しようとして失敗したか”を残す(運用で詰まらない)
- OSコマンドは「引用符」「待機」「終了コード」を必ず扱う
✅ 1) Application.Runを安全に使うラッパー
なぜこの書き方?
Application.Runは便利ですが、文字列指定のため保守性が落ちやすいです。
そこで「呼び出しを一か所」に寄せることで、マクロ名変更やブック構成変更があっても修正箇所を限定します。
別案との違い
直接 Application.Run "MacroName" を各所に散らすと、変更時に漏れやすいです。
ラッパー化すると、呼び出し側は「何をしたいか」だけを記述できます。
Option Explicit
'==================================================
' VBAマクロを安全に実行する
'==================================================
Public Sub RunMacroSafe(ByVal macroFullName As String, Optional ByVal args As Variant)
On Error GoTo ErrHandler
' argsが渡されない場合もあるので、存在チェックで分岐
If IsMissing(args) Then
Application.Run macroFullName
Else
Application.Run macroFullName, args
End If
Exit Sub
ErrHandler:
' 実務では「何を実行しようとして失敗したか」が重要
MsgBox "マクロ実行に失敗しました: " & macroFullName & vbCrLf & _
"エラー: " & Err.Number & " / " & Err.Description, vbExclamation
End Sub
実務の注意点
macroFullNameはできれば"BookName.xlsm!Module1.MacroName"の形で明示(曖昧さ排除)- ActiveWorkbook依存にしない(ThisWorkbook起点に寄せる)
- 引数が複数必要なら、Variant配列でまとめる設計にする(変更に強い)
✅ 2) WScript.Shell.Runを安全に使うラッパー(待機・引用符・終了コード)
なぜこの書き方?
WScript.Shell.Runは、パスのスペース・待機・exit codeが“事故ポイント”です。
ここを最初から吸収する共通関数にします。
別案との違い
Shell "cmd /c ..." で済ませる書き方もありますが、
- 待機が扱いづらい
- 引用符事故が増える
- exit codeが曖昧
になりやすいです。WScript.Shell.Runの方が運用が安定します。
Option Explicit
'==================================================
' 外部コマンドを実行する(WScript.Shell.Run)
' 戻り値: ExitCode(待機しない場合は -1)
'==================================================
Public Function RunCommandSafe( _
ByVal commandPath As String, _
Optional ByVal commandArgs As String = "", _
Optional ByVal windowStyle As Integer = 0, _
Optional ByVal waitOnReturn As Boolean = True _
) As Long
On Error GoTo ErrHandler
Dim shell As Object
Set shell = CreateObject("WScript.Shell")
Dim fullCommand As String
fullCommand = QuoteIfNeeded(commandPath)
If Len(Trim$(commandArgs)) > 0 Then
fullCommand = fullCommand & " " & commandArgs
End If
If waitOnReturn Then
RunCommandSafe = shell.Run(fullCommand, windowStyle, True)
Else
shell.Run fullCommand, windowStyle, False
RunCommandSafe = -1
End If
Exit Function
ErrHandler:
MsgBox "外部コマンド実行に失敗しました:" & vbCrLf & _
fullCommand & vbCrLf & _
"エラー: " & Err.Number & " / " & Err.Description, vbExclamation
RunCommandSafe = -9999
End Function
Private Function QuoteIfNeeded(ByVal path As String) As String
' スペースを含むパスを安全に扱う
If InStr(path, " ") > 0 Then
QuoteIfNeeded = """" & path & """"
Else
QuoteIfNeeded = path
End If
End Function
実務の注意点
commandArgs側にもスペースを含む引数があるなら、引数の引用符も設計する- PowerShell実行はポリシーや権限で失敗しやすいので、まずは手動で動作確認してからVBAに組み込む
waitOnReturn=TrueはExcelの操作が止まる。ユーザー操作が必要な外部アプリ起動では False が適する
Application.Run や WScript.Shell Run を使う場面では、
1つのプロシージャに処理を詰め込みすぎると、
実行の流れが追えなくなり、修正や切り分けが難しくなります。
実務では、
「実行する処理」と「実際の処理内容」を分けて設計することで、
保守性と再利用性を大きく高めることができます。
プロシージャ分割の考え方と実践方法は、次の記事で詳しく解説しています。
✅ 具体例:それぞれ「何を実行するか」を見える化
・Application.Run:別ブックのマクロを実行
- 月次ファイルを開いて、整形マクロを実行するようなケース
Public Sub Example_RunMacroInOtherWorkbook()
Dim targetWorkbookName As String
targetWorkbookName = "MonthlyReport.xlsm"
' ブックが開いている前提(未オープンなら開く処理を別で用意)
RunMacroSafe targetWorkbookName & "!Module1.FormatReport"
End Sub
・WScript.Shell.Run:バッチファイルを実行(待機する)
- CSV変換などを外部バッチに任せるケース
Public Sub Example_RunBatch()
Dim exitCode As Long
exitCode = RunCommandSafe("C:\Tools\convert_csv.bat", "", 0, True)
If exitCode <> 0 Then
MsgBox "バッチが正常終了しませんでした。ExitCode=" & exitCode, vbExclamation
End If
End Sub
✅ どちらを選んでも「実務で詰まらない」ためのチェックリスト
- 実行対象がVBAかOSか、最初に切り分けたか
- 実行文字列(macro名/コマンド)は1か所に集約したか
- 失敗時に「何を実行しようとして失敗したか」が残るか
- 同期/非同期の要件が明確か(待機で固まる事故を防ぐ)
- パスや引数のスペース、引用符を扱えているか
VBAで実行処理を増やしていくと、
気づかないうちにプロシージャが肥大化し、
「どこで何が動いているのか分からない」状態になりがちです。
Application.Run や外部実行を安全に使い続けるためには、
プロシージャのサイズを意識した設計が欠かせません。
プロシージャを適切な規模で管理する考え方については、
次の記事で整理しています。
Application.Run や WScript.Shell Run を使えば、
Excelからさまざまな処理を実行できるようになります。
ただし実務では、
「技術的にできるか」よりも
「そこまで自動化すべきか」「どこで止めるべきか」の判断の方が重要になる場面が少なくありません。
マクロや外部処理を増やす前に、
Excel業務改善をどの視点で判断すべきかを整理した記事があります。
✅ まとめ:Application.RunとWScript.Shell Runは「世界が違う」
- Application.Runは VBAマクロを実行する
- WScript.Shell.Runは Windowsの外部コマンド/アプリを実行する
- 実務では「待機」「引用符」「失敗時の情報」が運用品質を決める
- ラッパー化して呼び出しを集約すると、保守性が大きく上がる
「Run」という同じ名前に引っ張られず、
“何を実行するのか(VBAかOSか)” を先に固定すると、設計も実装もブレなくなります。