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 を終了させる──という自動化を組むときに発生しやすいエラーです。
| 項目 | 内容(例) |
|---|---|
| OS | Windows 10 |
| Office | PowerPoint 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)やマクロ名の見直し、タスクスケジューラ設定の調整へ進むと、手戻りが少なく安定した自動化に近づきます。

コメント