VBAテクニック集 VBA一覧 呼び出し処理 文法・構文

【VBA】実行の違いを整理|Application.RunとWScript.Shell Run

VBAで「何かを実行したい」と考えたとき、真っ先に候補に上がるのが Application.Run です。
一方で、外部プログラムやバッチ、PowerShell、別アプリを起動したい場面では WScript.Shell の Run が登場します。

ただ、実務ではここで混乱が起きます。

  • 「Run」という名前が同じで、同じものに見える
  • どこまでが“VBAの世界”で、どこからが“Windowsの世界”なのかが曖昧
  • エラー処理・待機・引数・セキュリティで後から詰まる

この記事では、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マクロを呼べるのでは?」
のような“すれ違い”が起きます。


✅ 使い分けの判断フロー(実務で迷わない軸)

次の質問に答えるだけで決まります。

  1. 実行したいのは VBAマクロ
    → はい:Application.Run
    → いいえ:次へ
  2. 実行したいのは Windowsの外部プログラム?(bat/cmd/exe/powershell等)
    → はい:WScript.Shell.Run
    → いいえ:次へ
  3. 実行後にExcel側は 待つ必要がある
    → 待つ:WScript.Shell.Run の bWaitOnReturn=True を検討
    → 待たない:False で非同期

このフローを記事の冒頭に置いておくと、読者は迷いません。


✅ Application.Runの特徴と実務の落とし穴

・何が得意か

  • マクロ名(文字列)で実行できる
  • 引数付きで呼べる(※呼び出し側がVariantで渡せる)
  • 「どのブックのマクロか」を意識して呼び分けできる

・実務での落とし穴

  • マクロ名を文字列で持つと、リネームに弱い(保守性低下)
  • 参照しているブック(ThisWorkbook/ActiveWorkbook)のズレで想定外を実行
  • ブックが閉じた/開いていないと呼べない(別ブックマクロ)

・“動けばOK”になりがちな悪い例

  • どのブックの何を呼ぶか曖昧
  • マクロ名のハードコード
  • エラー時に何が起きたか分からない

✅ WScript.Shell.Runの特徴と実務の落とし穴

・何が得意か

  • bat/cmd/exe/powershell など外部を起動できる
  • 引数(コマンドライン)を組める
  • 同期/非同期(待機)の選択ができる

・実務での落とし穴

  • パスにスペースがあると失敗(引用符の付け忘れ)
  • 実行環境(権限・パス・ポリシー)に依存
  • 何が失敗したかが分かりにくい(exit codeの扱い)

✅ 実務で壊れない実装パターン(設計意図つき)

ここからは、「再利用できる形」にすることを優先して、共通化したサンプルを提示します。

ポイントは3つです。

  1. 「実行」を1か所に集約して、呼び出し側を薄くする(変更に強くする)
  2. 失敗時に“何を実行しようとして失敗したか”を残す(運用で詰まらない)
  3. 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つのプロシージャに処理を詰め込みすぎると、
実行の流れが追えなくなり、修正や切り分けが難しくなります。

実務では、
「実行する処理」と「実際の処理内容」を分けて設計することで、
保守性と再利用性を大きく高めることができます。

プロシージャ分割の考え方と実践方法は、次の記事で詳しく解説しています。

【VBA】プロシージャを分割するメリットと実践方法


✅ 具体例:それぞれ「何を実行するか」を見える化

・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 や外部実行を安全に使い続けるためには、
プロシージャのサイズを意識した設計が欠かせません。

プロシージャを適切な規模で管理する考え方については、
次の記事で整理しています。

【VBA】プロシージャのサイズを適切に管理する方法

Application.Run や WScript.Shell Run を使えば、
Excelからさまざまな処理を実行できるようになります。

ただし実務では、
「技術的にできるか」よりも
「そこまで自動化すべきか」「どこで止めるべきか」の判断の方が重要になる場面が少なくありません。

マクロや外部処理を増やす前に、
Excel業務改善をどの視点で判断すべきかを整理した記事があります。

Excel業務改善はどう判断すべきか?ツール・自動化に迷う前の設計思考


 

✅ まとめ:Application.RunとWScript.Shell Runは「世界が違う」

  • Application.Runは VBAマクロを実行する
  • WScript.Shell.Runは Windowsの外部コマンド/アプリを実行する
  • 実務では「待機」「引用符」「失敗時の情報」が運用品質を決める
  • ラッパー化して呼び出しを集約すると、保守性が大きく上がる

「Run」という同じ名前に引っ張られず、
“何を実行するのか(VBAかOSか)” を先に固定すると、設計も実装もブレなくなります。

    -VBAテクニック集, VBA一覧, 呼び出し処理, 文法・構文