【VBA】Excelマクロを定期的に自動実行する

本ページはプロモーションが含まれています

Windowsの定期実行と言えばタスクスケジューラですが、Excelマクロを実行するにはクセがありまして直接指定することはできません

その昔はVBSとbatファイルを組み合わせていましたが、2023年10月にVBSが非推奨になったのでPowerShellでの実行プログラム作成タスクスケジューラ設定をご紹介します

PowerShellのサンプルプログラム

早速ですがまずはPowerShellのサンプルプログラムを

※Chatwork前提のプログラムなので適宜改修してください

# 最初に変数をまとめる
$excelFilePath = "C:\Users\javeo\Documents\テストマクロ.xlsm"  # マクロ入りファイルのフルパス
$macroNoArgs = "SampleMacro"                                  # 引数なしマクロ
$macroWithArgs = "ArgsMacro"                                  # 引数ありマクロ
$arg1 = "Hello"                                               # 引数その1
$arg2 = 12345                                                 # 引数その2
$token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"                   # 通知用チャットワークのトークン
$roomId = "000000000"                                         # 通知用チャットワークのルームID
$scriptPath = $MyInvocation.MyCommand.Path                    # このps1のフルパス

# ファイル有無を最初にチェック
if (-Not (Test-Path $excelFilePath)) {
    # ファイルが見つからなかったらチャットワークで通知する
    $message = "「$excelFilePath」が見つかりませんでした。`nパスを変更する場合は「$scriptPath」を修正してください。"
    Invoke-RestMethod -Uri "https://api.chatwork.com/v2/rooms/$roomId/messages" `
        -Method Post `
        -Headers @{ "X-ChatWorkToken" = $token } `
        -Body @{ body = $message }
    return
}

# エラーハンドリングしつつエクセルマクロを実行
try {
    # Excelアプリケーションを起動
    $excel = New-Object -ComObject Excel.Application
    $excel.Visible = $false                                    # 画面は非表示にしておく

    # エクセルファイルを開く
    $workbook = $excel.Workbooks.Open($excelFilePath)

    # マクロを実行する ※マクロに引数がある場合は値を続けて入力するだけ
    $excel.Run($macroNoArgs)
    $excel.Run($macroWithArgs, $arg1, $arg2)

    # ファイルを保存して閉じる
    $workbook.Close($true)
    $excel.Quit()
}
catch {
    # マクロでのエラーはキャッチできないはずなのでじつはこの分岐には来ないはず
    $message = "「$excelFilePath」でエラーが発生しました。"
    Invoke-RestMethod -Uri "https://api.chatwork.com/v2/rooms/$roomId/messages" `
        -Method Post `
        -Headers @{ "X-ChatWorkToken" = $token } `
        -Body @{ body = $message }}
finally {
    # 最後に各プロセスを開放する
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook) | Out-Null
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null
    [System.GC]::Collect()
    [System.GC]::WaitForPendingFinalizers()
}

PowerShellわからないよ“、って人でも最初の変数部分を変更するだけのテンプレで使えます

続いてパーツを分けて解説です

最初にマクロファイル有無チェック

最初にマクロファイルの有無をチェックします

# ファイル有無を最初にチェック
if (-Not (Test-Path $excelFilePath)) {
    # ファイルが見つからなかったらチャットワークで通知する
    $message = "「$excelFilePath」が見つかりませんでした。`nパスを変更する場合は「$scriptPath」を修正してください。"
    Invoke-RestMethod -Uri "https://api.chatwork.com/v2/rooms/$roomId/messages" `
        -Method Post `
        -Headers @{ "X-ChatWorkToken" = $token } `
        -Body @{ body = $message }
    return
}

私はChatwork利用者なので専用のトークルームにエラー通知するようにしていますが、他にも

  • Outlookでメール通知
  • メッセージボックス風に通知
  • BurntToastの通知(デスクトップ右下に出てくる通知)

とかやり方は様々

完全バックグラウンドで処理させるのでエラー発生時に何かしら通知する仕組みはあった方が吉です

とは言え、あった方がいい機能レベルなのでよくわからない場合は丸ごと削除しても問題ないです

一番大事なExcel操作部分

最低限ここさえあればOKなExcelマクロの実行部分

# Excelアプリケーションを起動
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false                                    # 画面は非表示にしておく

# エクセルファイルを開く
$workbook = $excel.Workbooks.Open($excelFilePath)

# マクロを実行する ※マクロに引数がある場合は値を続けて入力するだけ
$excel.Run($macroNoArgs)
$excel.Run($macroWithArgs, $arg1, $arg2)

# ファイルを保存して閉じる
$workbook.Close($true)
$excel.Quit()

マクロの中でエラーが発生してもExcel側で検知してしまい、PowerShell上ではエラーにならないので”try chatch“はただのおまじない

最後にオブジェクト(プロセス)を開放

finallyの中ですが説明用に切り出し

# 最後に各プロセスを開放する
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()

サイトによっては上2行だけの説明もありますが、なぜかExcel.exeのプロセスが残るときがあるのでこの4行を書いておくのが安心

タスクスケジューラの設定

続いてタスクスケジューラ側の設定です

各タブに説明付けますが大事なのは結局大事なのは”操作タブ”です

“全般”タブ

特に説明するようなことはないタブ

名前と説明はお好きに設定してもらってセキュリティオプション以下は基本何も触らなくてOK

“トリガー”タブ

ここも特に説明することはないので、実行頻度に合わせて各設定をどうぞ

“操作”タブ

ここがちょっとミソポイント

2パターンの設定がありまして後半の設定がおススメです

普通にPowerShellを実行する場合

まずはサンプル画像

“PowerShellをタスクスケジューラで設定する”と言われればこの設定が一般的

ただこれだとここれだとコンソール画面(真っ黒な画面)が立ち上がるのでそれが嫌な人は後半の設定へ

コンソール画面は動いていることを確認できるし、処理状況もわかるメリットもあるのでコンソール画面の表示・非表示はお好みで

“プログラム/スクリプト”

普通はpowershell.exeだけで大丈夫なはず

もし動かない場合などフルパスで書くなら

  • C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
  • C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe

のどちらかにexeファイルがあるはず

引数の追加(オプション)

画像は見切れていますが記載しているのは

-ExecutionPolicy Bypass -File "C:\Users\javeo\Documents\excel-macro-auto-run.ps1"

-ExecutionPolicy Bypass“で実行ポリシーを制限無視にしておくのがポイント

-File“の後ろに上部で作成したPowerShellファイル(ps1ファイル)のフルパスを記載

開始(オプション)

設定しなくても動く(はず)

PowerShellファイルが保存し手あるフォルダを設定するのがおまじない

コンソール画面を出さずにPowerShellを実行する場合

こちらもまずはサンプル画面

conhost.exe“と引数の”–headless powershell.exe“にすることでコンソール画面を非表示で実行することが可能になります

プログラム/スクリプト

ここもconhost.exeだけで大丈夫なはず

フルパスで書くなら

  • C:\Windows\System32\conhost.exe

にいるはず

ちなみにconhost.exeとは

conhost.exe は、**Console Window Host(コンソール ウィンドウ ホスト)**の略で、Windowsオペレーティングシステムの一部です。主に コマンドプロンプト(cmd.exe)や PowerShell などのコンソールアプリケーションの表示と操作をサポートする役割 を担っています。

ってことで、実はPowerShellを実行したときに表示されるコンソール画面もconhost.exeなんですね

PowerShellを実行しようとした時にconhostと一緒に起動するか、conhostを起動して中でPowerShellを実行するのか、の起動方法の違いで実際はほぼ同じです

引数の追加(オプション)

PowerShellを実行する場合と理屈は同じ

--headless powershell.exe -NoProfile -ExecutionPolicy Bypass -File"C:\Users\javeo\Documents\excel-macro-auto-run.ps1"

conhost.exeから画面非表示なので”–headless powershell.exe“を指定するだけ

-NoProfile“はなくてもよさそうだけどここもおまじない

それ以降はPoweShell実行時と同じ引数で

開始(オプション)

ここはPowerShellとおなじ

“条件”タブ

特に触る必要はないはず

使い方によっては”タスクを実行するためにスリープを解除する“にチェックを入れたほうがいいかも

“設定”タブ

ここも特に触る必要はない

“タスクが既に実行中の場合に適用される規則”はプログラムの仕様に合わせて変えていいかもです

あとがき

ここまで書いといてなんですが、、正直私はExcelはUI前提のアプリだと思っているタイプなのでマクロをバックグラウンドで定期実行することはあまり推奨したくありません

ですが、Excelは汎用性高すぎる超絶便利アプリなのは否定できず、需要ありそうなのでまとめてみました(まとめてるってことはなんだかんだで私も使ってます)

世の中的に脱Excelをよく聞きますがなんだかんだで便利ですよね

コメント

タイトルとURLをコピーしました