PowerShellでPowerPointのVBAマクロを実行する方法|Application.Run「引数1つのオーバーロードが無い」エラー対処

PowerShell から PowerPoint を COM 起動して .pptm を開き、VBA マクロを自動実行して閉じたいのに、Application.Run が「Cannot find an overload for ‘Run’ and the argument count: ‘1’(引数1つのオーバーロードが無い)」で止まることがあります。本記事では原因(省略可能引数と COM バインドの罠)と、現場で安定稼働させる回避策をまとめます。

目次

結論:Run を 2 引数で呼び、2つ目に [Type]::Missing を渡す

このエラーは、マクロの中身よりも Application.Run の呼び出し形(省略可能引数の扱い)で起きることが多いです。まずは PowerShell 側を次の形に変えるだけで解消するケースがあります。

$ppt.Run("mailme", [Type]::Missing) | Out-Null

マクロ名は Module1.mailme のようにモジュール名まで含めるより、まずは mailme のように短く指定した方が安定しやすいです。次に、名前解決やマクロ配置、セキュリティ設定、タスクスケジューラの実行方式を順番に潰していきます。

優先度対処狙い
高$ppt.Run("mailme", [Type]::Missing)「1 引数で Run が見つからない」を最短で回避
中Reflection(InvokeMember)で Run を呼ぶPowerShell のメソッド解決を迂回して相性問題を回避
中マクロ名/配置(標準モジュール、Public Sub)を見直す「Sub or function not defined」を潰す
中マクロ有効化(信頼できる場所、警告の有無)を確認非表示実行でセキュリティプロンプト停止を防ぐ
低タスクスケジューラの実行方式を調整対話セッション前提の挙動で詰まるのを回避

現象:PowerShell から Application.Run が 1 引数で失敗する

Windows 10 と PowerPoint 2016(Office 2016 Pro)で、PowerShell(.ps1)から PowerPoint を COM 起動し、マクロ有効プレゼン(.pptm)を開いて VBA マクロを実行し、処理後に PowerPoint を終了させる──という自動化を組むときに発生しやすいエラーです。

項目内容(例)
OSWindows 10
OfficePowerPoint 2016(Office 2016 Pro)
起動方法PowerShell から COM(New-Object -ComObject PowerPoint.Application)
やりたいこと.pptm を開く → VBA マクロ(例:mailme)実行 → 閉じる
エラー例Cannot find an overload for "Run" and the argument count: "1"

マクロ自体は PowerPoint 上で手動実行すると正常に動くのに、PowerShell 経由だと $ppt.Run("Module1.mailme") のような 1 引数呼び出しで失敗する、というのが典型パターンです。

原因の本質:COM の「省略可能引数」が PowerShell のメソッド解決を壊す

PowerPoint の Application.Run は、VBA の世界では「マクロ名 + 必要なら引数」という感覚で気軽に呼べます。しかし COM 経由(PowerShell から)になると、内部的には「省略可能引数(オプション引数)を大量に持つメソッド」として公開されているため、PowerShell が “1 引数の Run” を見つけられずに例外を投げることがあります。

イメージとしては、Run の呼び出し形が次のように定義されていることがポイントです(概念図)。

VBA での見え方COM/Interop 側の見え方(概念)
Application.Run "mailme"Run(MacroName, [Arg1], [Arg2], ...) のように、任意個の引数を受けられる
引数を省略できる実体は「引数が多い 1 つのメソッド」だが、PowerShell が省略可能引数をうまく解釈できない場合がある

結果として、PowerShell からは「引数が 1 個の Run は存在しない」と判定され、次のようなエラーに繋がります。

  • Cannot find an overload for "Run" and the argument count: "1"

ここで重要なのは、マクロが壊れているのではなく、PowerShell から COM を叩く “入口” の問題 だという点です。マクロが PowerPoint 内で動くなら、まずは Run の呼び方を疑うのが近道になります。

対処:Run を “引数付き” で呼ぶ(ダミーでも可)

実務で一番ラクに効きやすいのが、Run を 1 引数ではなく 2 引数以上で呼ぶ方法です。PowerShell 側で引数を 1 つ足すだけでメソッド解決が通り、エラーが消えることがあります。

ただし、ここで気を付けたいのが 「ダミー引数の種類」 です。"" や $null を渡すと “マクロに引数が渡った扱い” になるため、VBA 側が引数を受け取れないと「引数の数が違います」系のエラーに繋がります。一方で [Type]::Missing は “省略した扱い” になりやすく、マクロが引数なしでも動かしやすいため安全です。

呼び出し例狙い注意点
$ppt.Run("mailme", [Type]::Missing)PowerShell 側は 2 引数、COM 側は「省略」扱いに寄せるマクロが引数なしでも動かしやすい。まずはこれを推奨
$ppt.Run("mailme", "")2 引数にしてバインドを通すVBA 側が 1 引数を受け取れる必要あり(下の VBA 例参照)
$ppt.Run("mailme", $null)2 引数にしてバインドを通すVBA 側が 1 引数を受け取れる必要あり。Variant で受けると吸収しやすい

VBA 側を “自動化に強い形” にする(引数を吸収する)

空文字や Null をダミー引数として渡す運用をするなら、マクロ側を次のようにしておくと安定します。

' 標準モジュール(Module1 など)に配置
Public Sub mailme(Optional dummy As Variant)
  ' ここに本来の処理
  ' dummy は使わなくてもOK(空/Null を受けても落ちにくくするための保険)
End Sub

「引数を増やすのは気持ち悪い」と感じるかもしれませんが、Office の COM 自動化では “安定稼働が最優先” になりがちです。VBA 側が 1 引数を吸収できるだけで、PowerShell 側の呼び出しの自由度が上がります。

実務向け:PowerShell で pptm を開いてマクロ実行→閉じるサンプル

以下は「PowerPoint を COM 起動 → pptm を開く → マクロ実行 → 閉じる → COM 解放」を 1 本にまとめた例です。タスクスケジューラ運用も想定し、後処理(Quit / ReleaseComObject / GC)まで入れています。

param(
  [Parameter(Mandatory = $true)]
  [string]$PptmPath
)

$ErrorActionPreference = "Stop"

# Office COM は VARIANT_BOOL を使うため、真偽値は -1 / 0 が無難
$msoTrue  = -1
$msoFalse = 0

$ppt  = $null
$pres = $null

try {
  # PowerPoint 起動
  $ppt = New-Object -ComObject PowerPoint.Application

  # まずは可視化($msoTrue)で検証すると切り分けが早い
  # 運用で非表示にするなら $msoFalse に変更
  $withWindow = $msoTrue

  # プレゼンを開く(一般的に FileName, ReadOnly, Untitled, WithWindow の順)
  $pres = $ppt.Presentations.Open($PptmPath, $msoFalse, $msoFalse, $withWindow)

  # 画面表示で開いた場合は、念のためアクティブ化(環境差対策)
  if ($withWindow -eq $msoTrue -and $pres.Windows.Count -ge 1) {
    $pres.Windows.Item(1).Activate() | Out-Null
  }

  # ★重要:Run を 1 引数ではなく 2 引数で呼ぶ
  # [Type]::Missing は「省略した扱い」になりやすく、マクロが引数なしでも動かしやすい
  $ppt.Run("mailme", [Type]::Missing) | Out-Null

  # 必要なら保存
  # $pres.Save()

  # 閉じる
  $pres.Close()
}
catch {
  # ログに残したい場合はここで Write-EventLog などへ
  throw
}
finally {
  # PowerPoint 終了
  if ($ppt -ne $null) {
    try { $ppt.Quit() } catch {}
  }

  # COM 解放(POWERPNT.EXE が残るのを防ぎやすい)
  if ($pres -ne $null) {
    [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($pres)
  }
  if ($ppt -ne $null) {
    [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($ppt)
  }

  [GC]::Collect()
  [GC]::WaitForPendingFinalizers()
  [GC]::Collect()
  [GC]::WaitForPendingFinalizers()
}

ポイントは次の通りです。

  • Run は 2 引数以上で呼ぶ(まずは [Type]::Missing 推奨)
  • 最初の検証は WithWindow を表示($msoTrue) にして、セキュリティ警告の有無を目視で潰す
  • 終了時は Quit と ReleaseComObject を入れて、プロセス残り(POWERPNT.EXE が残留)を減らす

特にタスクスケジューラ運用では、プロセス残りが累積すると次回実行が失敗したり、ファイルがロックされたりします。「正常系のスクリプト」ほど finally の後片付けが重要になります。

回避策その2:Reflection(InvokeMember)で Run を呼ぶ

ダミー引数で安定しない環境や、「どうしても PowerShell の $ppt.Run() から抜け出したい」という場合は、.NET Reflection の InvokeMember を使って COM メソッド呼び出しを行う方法があります。PowerShell のメソッド解決を迂回できるため、オプション引数絡みの相性問題を回避できることがあります。

# $ppt は New-Object -ComObject PowerPoint.Application で作成済みとする

$macro = "mailme"

$bindingFlags =
  [System.Reflection.BindingFlags]::InvokeMethod -bor
  [System.Reflection.BindingFlags]::Public -bor
  [System.Reflection.BindingFlags]::Instance

$ppt.GetType().InvokeMember(
  "Run",
  $bindingFlags,
  $null,
  $ppt,
  @($macro, [Type]::Missing)
) | Out-Null

ここでも [Type]::Missing を添えるのがコツです。「PowerShell の $ppt.Run() では落ちるのに、Reflection だと動く」というケースは珍しくありません。

マクロ名の指定でつまずくポイント(Module1.mailme が通らない等)

「オーバーロード問題」を回避して Run が呼べるようになった後、次に出やすいのが次のエラーです。

  • Application.Run : Invalid request. Sub or function not defined.

これは多くの場合、マクロ名の名前解決(どのプレゼンのどのモジュールの Sub を指しているか)が一致していないか、そもそも 外部から呼べる形で公開されていない ことが原因です。

指定例意味使いどころ
mailme名前だけで解決を試みるまずはここから。単一ファイル運用なら一番ラク
Module1.mailmeモジュール名 + マクロ名同名マクロがあるときの切り分け。ただし外部呼び出しで揺れることも
プレゼン名!mailmeファイルを明示して実行(Office 系で一般的な書式)複数のプレゼンやアドインを開く運用で、参照先を固定したいとき

外部からの Run は、VBE 内での実行よりも「どこにあるマクロか」を厳密に要求する傾向があります。自動化ではまず、標準モジュールに Public Sub mailme() を置き、名前は短く、引数は無し(または省略可能)に寄せると安定します。

「Sub or function not defined」になるときのチェックリスト

チェック項目OK の条件NG になりやすい例
標準モジュールにあるかVBE の「標準モジュール(Module1 等)」に Public Sub mailme()ThisPresentation / クラスモジュール内の Sub をそのまま呼ぼうとしている
公開スコープPublic Sub で宣言されているPrivate Sub になっている
マクロ名の表記まずは mailme のみで試すModule1.mailme に固執している
対象ファイルが正しいか開いた pptm の中に目的の Sub が存在する同名マクロが別ファイルにあり、意図せずそちらを参照している
マクロが有効か警告が出ず、マクロが実行できる状態保護ビュー/ブロック/セキュリティ警告が出ている(非表示実行だと止まる)

マクロが “無効化されている” ときに起きる症状と対策

COM 自動化で厄介なのが、マクロが無効化されている/セキュリティプロンプトが出ているのに画面が出ていない、というパターンです。手動実行だと「コンテンツの有効化」をクリックできるため気づきにくいのですが、タスクとして回すとそこで止まります。

症状ありがちな原因実務での対策
マクロが呼ばれない/反応がないセキュリティ警告が出ている(非表示実行だと操作できない)検証時は WithWindow を表示にして警告の有無を確認。運用は「信頼できる場所」に配置して警告を出さない
Invalid request / Sub not definedマクロ名が解決できていない/VBA が無効標準モジュール + Public Sub に寄せ、まずは短い名前で呼ぶ
pptm を開くときに止まる保護ビュー、インターネット由来のブロック、アクセス権ファイルのブロック解除、社内配布場所への移動、署名付きマクロの検討

「自動でマクロを動かす」のは便利ですが、セキュリティの観点ではリスクもあります。運用では “セキュリティを下げる” のではなく、信頼できる場所・署名・配布経路 の整理で、ユーザー操作なしに安全に動く状態を作るのが理想です。

タスクスケジューラ運用でトラブルを減らす設定

Office の COM 自動化は、一般に “対話セッション前提” の挙動になりやすく、スケジューラでのバックグラウンド実行と相性がよくありません。Windows 10 上で定期実行する場合は、タスク側の設定も含めて安定化させるのがコツです。

設定項目おすすめ理由
実行方法「ユーザーがログオンしているときのみ実行」UI/セキュリティダイアログが出る場合に詰まりにくい。Office 自動化の前提に合わせやすい
PowerShell 実行powershell.exe -NoProfile -File "C:\path\run.ps1"プロファイル差分で動作が揺れるのを避ける(実行ポリシーは環境の規程に合わせて運用)
開始(作業フォルダー)スクリプトのあるフォルダーを指定相対パスやログ出力先が迷子になりにくい
同時起動対策二重起動を禁止(ミューテックスやロックファイル)PowerPoint の COM は多重起動で不安定になりやすい

また、Office と PowerShell のビット数(32bit/64bit)が噛み合わないと、COM 生成そのものが失敗することがあります。今回の「オーバーロードが無い」エラーとは別ですが、PowerPoint.Application の生成に失敗している場合は、Office と同じビット数の PowerShell で試す、という切り分けも有効です。

COM 自動化を安定させる小技

  • 例外が起きても必ず Quit する:try/finally を徹底し、PowerPoint のプロセス残りを防ぐ
  • Presentation を変数で保持する:開いたオブジェクトに対して Close する。アクティブ依存を減らす
  • ログを残す:タスク運用では “何も起きない” が一番困る。最低限、開始/終了/例外をテキストに出す
  • 最初は可視化して検証:WithWindow を表示にして、警告やダイアログの有無を目視で潰す
  • マクロ側を自動化向けに設計:引数なし(または Optional)、Public、標準モジュール、外部依存(ダイアログ表示)を避ける

まとめ:最短で直すなら “Run を 2 引数で呼ぶ”

PowerShell から PowerPoint の VBA マクロを実行する際の「引数1つのオーバーロードが無い」問題は、マクロではなく Application.Run の省略可能引数と COM バインドの相性で起きるケースが多いです。まずは $ppt.Run("mailme", [Type]::Missing) のように “引数付き(省略扱い)” で呼び、次に Reflection(InvokeMember)やマクロ名の見直し、タスクスケジューラ設定の調整へ進むと、手戻りが少なく安定した自動化に近づきます。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次