この記事でわかること
- ブックを開いたときに自動実行する方法(Workbook_Open)
- 保存するときに自動チェックを入れる方法(Workbook_BeforeSave)
- 開く→データ更新→保存時バックアップ→閉じる前ログ記録を自動化する方法
対象: Excel 2016以降 / Microsoft 365、Windows 10/11
—
どんな場面で使う?
- ブックを開いたときに自動でデータを更新・集計したい
- 保存前に必須項目の空欄チェックを自動で走らせたい
- 保存時にバックアップファイルを自動作成したい
- ブックを閉じるときにログを記録して操作履歴を残したい—
完成イメージ(Before / After)
Before(手動で毎回マクロ実行・目視チェック):
| 操作 | 所要時間 |
|---|---|
| ブックを開いて手動でマクロ実行 | 毎回30秒 |
| 保存前に空欄がないか目視確認 | 毎回1〜2分 |
| バックアップを手動でコピー | 毎回1分 |
After(イベント処理で全自動):
| 操作 | 所要時間 |
|---|---|
| ブックを開くだけで自動実行 | 0秒(自動) |
| 保存するだけで空欄チェック | 0秒(自動) |
| 保存時にバックアップも自動作成 | 0秒(自動) |
—
自分も以前、ブックを開くたびに Alt+F8 で集計マクロを手動実行していた。毎朝同じ操作を繰り返すのが正直めんどくさかった。Workbook_Open にコードを入れてからは、ブックを開くだけで最新データに更新されるようになった。朝の手作業が完全になくなった。この記事で「開いたら勝手に動く」仕組みをサクッと作れるようになってほしい。
ポイント: このイベント処理のコードは、通常のマクロと貼り付け場所が違う。標準モジュール(Module1)ではなく「ThisWorkbook」モジュールに書く。ここを間違えると動かない。
なお、セルの値が変わったときに自動実行する方法は セルの値が変わったら自動実行(Worksheet_Change) で解説している。今回はその「ブック版」にあたる。
—
実行前の準備
バックアップを取る
イベント処理は意図しないタイミングで実行されることがある。必ずファイルのコピーを別フォルダに保存してから作業する。
Excelをマクロ有効ブック(.xlsm)で保存する
拡張子が .xlsx のままだとマクロが保存できない。
- 「ファイル」→「名前を付けて保存」
- ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
- 保存
シート構成を確認する(実務版で使用)
実務版コードは以下のシート構成を前提としている:
| シート名 | 用途 |
|---|---|
| データ | 元データ(A列に数値) |
| 集計 | 集計結果(B2に合計値、A1に最終更新日時) |
| ログ | 操作ログ(日時・操作・ユーザー名)※なければ自動作成 |
基本版・応用版はシート構成を問わない。
—
手順(コピペ → 動作確認まで約5分)
1. VBE(コードを書く画面)を開く
Excelで Alt + F11 を押す。
2. ThisWorkbook モジュールを開く(ここが最重要)
標準モジュールではない。 VBEの左側「プロジェクトエクスプローラー」で以下を探す:
VBAProject (ファイル名.xlsm)
└─ Microsoft Excel Objects
├─ Sheet1 (Sheet1)
├─ Sheet2 (Sheet2)
└─ ThisWorkbook ← ★ここをダブルクリック
ThisWorkbook をダブルクリックすると、右側にコードウィンドウが開く。
3. イベントプロシージャを自動生成する
コードウィンドウ上部に2つのドロップダウンがある:
- 左のドロップダウンから「Workbook」を選択
- 右のドロップダウンからイベント名(Open / BeforeSave / BeforeClose)を選択
- プロシージャの枠(
Private Sub ... End Sub)が自動で挿入される
この方法なら、プロシージャ名のスペルミスを防げる。
4. コードを貼り付けて保存する
自動生成されたプロシージャの中に、下のコードの中身を貼り付ける。貼り付けたらブックを保存して閉じ、再度開いて動作を確認する。
ボタンに割り当てて手動でも実行したい場合は マクロをボタン1つで実行する方法 を参照。ただしイベントプロシージャは Private Sub なので、ボタンに割り当てるには別途標準モジュールに呼び出し用の Sub を作る必要がある。
—
コード(基本版)– Workbook_Open で起動時メッセージ表示
まずは最小限のコードで動作を確認する。ブックを開いたときにメッセージが表示されれば成功。
'============================================================
' ■ ブックを開いたとき自動実行(基本版)
' → ブックを開くとメッセージを表示
' → 貼り付け場所: ThisWorkbook モジュール
'============================================================
Private Sub Workbook_Open()
'--- ★書き換えポイント ---
Dim msg As String
msg = "データを更新しました。" '← 表示するメッセージ
'--- ★ここまで ---
MsgBox msg, vbInformation, "自動実行"
End Sub
書き換えポイント
| 変数 | 説明 | 初期値 |
|---|---|---|
msg |
起動時に表示するメッセージ | "データを更新しました。" |
確認方法: コードを貼り付けたら、ブックを保存して閉じる。再度ブックを開いたときにメッセージが出れば成功。
—
コード(応用版)– Workbook_BeforeSave で保存前チェック(空欄警告)
保存しようとしたとき、指定範囲に空欄がないかチェックする。空欄があれば警告を出し、保存をキャンセルするか選べる。
'============================================================
' ■ 保存前に空欄チェック(応用版)
' → Ctrl+S や上書き保存の前に自動チェック
' → 空欄があれば警告して保存を中止(キャンセル可)
' → 貼り付け場所: ThisWorkbook モジュール
'============================================================
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
'--- ★書き換えポイント ---
Dim checkSheet As String
checkSheet = "Sheet1" '← チェック対象のシート名
Dim checkRange As String
checkRange = "A2:D20" '← チェック対象の範囲
'--- ★ここまで ---
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets(checkSheet)
Dim rng As Range
Set rng = ws.Range(checkRange)
'--- 空欄を検出
Dim emptyCell As Range
Dim emptyCount As Long
emptyCount = 0
For Each emptyCell In rng
If emptyCell.Value = "" Then
emptyCount = emptyCount + 1
End If
Next emptyCell
'--- 空欄がなければそのまま保存
If emptyCount = 0 Then Exit Sub
'--- 空欄があれば警告
Dim ans As VbMsgBoxResult
ans = MsgBox(checkSheet & " の " & checkRange & " に空欄が " & emptyCount & " 個あります。" & vbCrLf & vbCrLf & _
"このまま保存しますか?", vbYesNo + vbExclamation, "保存前チェック")
If ans = vbNo Then
Cancel = True '← 保存をキャンセル
MsgBox "保存をキャンセルしました。空欄を確認してください。", vbInformation
End If
End Sub
書き換えポイント
| 変数 | 説明 | 初期値 |
|---|---|---|
checkSheet |
チェック対象のシート名 | "Sheet1" |
checkRange |
チェック対象の範囲 | "A2:D20" |
ポイント: Cancel = True にすると保存が中止される。ユーザーに「保存するかどうか」を選ばせるダイアログを入れているので、強制キャンセルにはならない。
指定時刻にマクロを自動実行したい場合は 指定時刻にマクロを自動実行する方法(Application.OnTime) を参照。イベントトリガーと時刻トリガーは使い分けると便利。
—
コード(実務版)– 開く→データ更新→保存時バックアップ→閉じる前ログ記録
実務では複数のイベントを組み合わせて使うことが多い。この実務版では以下の3つを自動化する:
- ブックを開いたとき: 集計シートのデータを更新
- 保存するとき: バックアップファイルを自動作成
- 閉じる前: ログシートに操作日時を記録
この仕組みを入れてからは、ブックを開いたらデータ更新、保存時にバックアップ、閉じる前にログ記録という一連の流れが全自動で回っている。手作業ゼロで管理できるのが快適。もっと早く知りたかった。
'============================================================
' ■ ブックイベント一括管理(実務版)
' → 開く: データ更新 / 保存: バックアップ / 閉じる前: ログ記録
' → 貼り付け場所: ThisWorkbook モジュール
' → すべてのコードをThisWorkbookに貼り付ける
'============================================================
'------------------------------------------------------------
' 【1】ブックを開いたとき: データ更新
'------------------------------------------------------------
Private Sub Workbook_Open()
On Error GoTo ErrHandler
'--- ★書き換えポイント ---
Dim srcSheet As String
srcSheet = "データ" '← 元データのシート名
Dim dstSheet As String
dstSheet = "集計" '← 集計先のシート名
Dim srcRange As String
srcRange = "A2" '← 元データの開始セル
Dim dstCell As String
dstCell = "B2" '← 集計値を書き込むセル
'--- ★ここまで ---
Application.EnableEvents = False '← イベントの二重実行を防ぐ
Dim wsSrc As Worksheet
Set wsSrc = ThisWorkbook.Worksheets(srcSheet)
Dim wsDst As Worksheet
Set wsDst = ThisWorkbook.Worksheets(dstSheet)
'--- 元データの最終行を取得
Dim lastRow As Long
lastRow = wsSrc.Cells(wsSrc.Rows.Count, "A").End(xlUp).Row
'--- 合計値を集計シートに転記
If lastRow >= 2 Then
wsDst.Range(dstCell).Value = Application.WorksheetFunction.Sum( _
wsSrc.Range(srcRange & ":" & wsSrc.Cells(lastRow, "A").Address))
End If
wsDst.Range("A1").Value = "最終更新: " & Format(Now, "yyyy/mm/dd hh:nn:ss")
MsgBox "データを更新しました(" & Format(Now, "hh:nn") & ")", vbInformation, "自動更新"
Cleanup:
Application.EnableEvents = True '← 必ず戻す
Exit Sub
ErrHandler:
MsgBox "データ更新でエラーが発生しました。" & vbCrLf & _
"エラー内容: " & Err.Description, vbExclamation
Resume Cleanup
End Sub
'------------------------------------------------------------
' 【2】保存するとき: バックアップファイルを自動作成
'------------------------------------------------------------
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
On Error GoTo ErrHandler
'--- ★書き換えポイント ---
Dim backupFolder As String
backupFolder = ThisWorkbook.Path & "\backup" '← バックアップ先フォルダ
'--- ★ここまで ---
Application.EnableEvents = False
'--- バックアップフォルダがなければ作成
If Dir(backupFolder, vbDirectory) = "" Then
MkDir backupFolder
End If
'--- バックアップファイル名(日時付き)
Dim backupName As String
backupName = backupFolder & "\" & _
Replace(ThisWorkbook.Name, ".xlsm", "") & _
"_" & Format(Now, "yyyymmdd_hhnnss") & ".xlsm"
'--- バックアップを作成
ThisWorkbook.SaveCopyAs backupName
Cleanup:
Application.EnableEvents = True
Exit Sub
ErrHandler:
MsgBox "バックアップの作成でエラーが発生しました。" & vbCrLf & _
"エラー内容: " & Err.Description, vbExclamation
Resume Cleanup
End Sub
'------------------------------------------------------------
' 【3】閉じる前: ログシートに操作日時を記録
'------------------------------------------------------------
Private Sub Workbook_BeforeClose(Cancel As Boolean)
On Error GoTo ErrHandler
'--- ★書き換えポイント ---
Dim logSheet As String
logSheet = "ログ" '← ログ記録先のシート名
'--- ★ここまで ---
Application.EnableEvents = False '← イベントの二重実行を防ぐ
'--- ログシートが存在するか確認
Dim wsLog As Worksheet
On Error Resume Next
Set wsLog = ThisWorkbook.Worksheets(logSheet)
On Error GoTo ErrHandler
If wsLog Is Nothing Then
'--- ログシートがなければ作成
Set wsLog = ThisWorkbook.Worksheets.Add( _
After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
wsLog.Name = logSheet
wsLog.Range("A1").Value = "日時"
wsLog.Range("B1").Value = "操作"
wsLog.Range("C1").Value = "ユーザー"
End If
'--- 最終行の次にログを追記
Dim nextRow As Long
nextRow = wsLog.Cells(wsLog.Rows.Count, "A").End(xlUp).Row + 1
wsLog.Cells(nextRow, "A").Value = Format(Now, "yyyy/mm/dd hh:nn:ss")
wsLog.Cells(nextRow, "B").Value = "ブックを閉じる"
wsLog.Cells(nextRow, "C").Value = Application.UserName
'--- 保存してから閉じる
' ※ EnableEvents=False中なのでBeforeSaveは再発火しない
ThisWorkbook.Save
Cleanup:
Application.EnableEvents = True '← 必ず戻す
Exit Sub
ErrHandler:
MsgBox "ログ記録でエラーが発生しました。" & vbCrLf & _
"エラー内容: " & Err.Description, vbExclamation
Resume Cleanup
End Sub
書き換えポイント
| 変数 | 説明 | 初期値 |
|---|---|---|
srcSheet |
元データのシート名(Open用) | "データ" |
dstSheet |
集計先のシート名(Open用) | "集計" |
srcRange |
元データの開始セル(Open用) | "A2" |
dstCell |
集計値の書き込みセル(Open用) | "B2" |
backupFolder |
バックアップ先フォルダ(BeforeSave用) | ThisWorkbook.Path & "\backup" |
logSheet |
ログ記録先のシート名(BeforeClose用) | "ログ" |
ファイルの自動保存やバックアップの詳細は ブックを自動保存する方法 も参照。
—
よくある落とし穴5選
1. コードを標準モジュールに書いて「動かない」
自分もこれで30分溶かした。Workbook_Open のコードを Module1 に書いてしまい、ブックを開いても何も起きなかった。原因は単純で、イベントプロシージャは ThisWorkbook モジュールにしか書けない。
| 症状 | 原因 | 対策 |
|---|---|---|
| ブックを開いても何も起きない | コードが Module1 にある | VBEの左側で「ThisWorkbook」をダブルクリックしてコードを移動する |
2. プロシージャ名のスペルミスで認識されない
| 症状 | 原因 | 対策 |
|---|---|---|
| 正しい場所に書いたのに動かない | Workbook_open WorkBook_Open などスペルが違う |
コードウィンドウ上部のドロップダウンから自動生成する。手入力しない |
3. EnableEvents = False を戻し忘れて全イベントが停止
| 症状 | 原因 | 対策 |
|---|---|---|
| 1回目は動くが、2回目以降すべてのイベントが動かない | EnableEvents = False のまま放置 | On Error GoTo で必ず True に戻す。実務版コードのように Cleanup ラベルを使う |
応急処置: イミディエイトウィンドウ(Ctrl+G)で Application.EnableEvents = True を実行すれば復旧する。
4. BeforeClose で Cancel = True にしたらブックが閉じられない
| 症状 | 原因 | 対策 |
|---|---|---|
| ×ボタンを押してもブックが閉じない | 無条件に Cancel = True を設定している | 特定の条件でのみ Cancel = True にする。デバッグ中は一時的にコメントアウトする |
5. マクロのセキュリティ設定でイベントがブロックされる
| 症状 | 原因 | 対策 |
|---|---|---|
| 自分のPCでは動くが別のPCで動かない | マクロが無効になっている | 「コンテンツの有効化」をクリックする。または「ファイル→オプション→セキュリティセンター→信頼できる場所」にフォルダを追加する |
—
VBAのWorkbook_Openが動かないときの対処法
「Workbook_Openを書いたのにブックを開いても何も起きない」という場合、原因はコードを標準モジュールに書いていることが多い。Workbook_OpenはThisWorkbookモジュールに書く必要がある。VBEの左側ツリーで「ThisWorkbook」をダブルクリックして開き、そこにコードを貼り付けること。
VBAのEnableEventsがFalseのまま戻らなくなったときの対処法
「イベント処理が全く動かなくなった」という場合、原因はどこかで Application.EnableEvents = False を設定したまま戻し忘れていることだ。イミディエイトウィンドウで Application.EnableEvents = True を直接実行すれば復旧する。
FAQ
Q1: Worksheet_Change と Workbook_Open は何が違う?
| 比較項目 | Worksheet_Change | Workbook_Open / BeforeSave |
|---|---|---|
| トリガー | セルの値が変わったとき | ブックを開いたとき / 保存するとき |
| 発火頻度 | セル変更のたび(高頻度) | ブック操作時(低頻度) |
| 貼り付け場所 | シートモジュール(Sheet1等) | ThisWorkbook モジュール |
| 主な用途 | 入力に応じた即時処理 | 起動時の初期化・保存前チェック |
詳しくは セルの値が変わったら自動実行(Worksheet_Change) を参照。
Q2: Workbook_Open で重い処理を入れたらブックの起動が遅くなる?
はい。重い処理(大量データ集計、外部ファイル読み込みなど)を入れると、ブックが開くまで時間がかかる。対策は2つ:
Application.ScreenUpdating = Falseで画面更新を止めて処理を高速化するApplication.OnTime Now + TimeValue("00:00:01"), "処理名"で1秒遅延させてから実行する(ブック自体はすぐ開く)
Q3: BeforeSave の SaveAsUI パラメータは何?
SaveAsUI は Boolean 値。True = 「名前を付けて保存」、False = 「上書き保存」。処理を分けたい場合に使う:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If SaveAsUI Then
'--- 「名前を付けて保存」のときだけ実行する処理
Else
'--- 「上書き保存」のときだけ実行する処理
End If
End Sub
Q4: イベントを一時的に無効にしたいときは?
Application.EnableEvents = False で全イベントを一時停止できる。処理後に必ず True に戻すこと。 戻し忘れの応急処置は、イミディエイトウィンドウ(Ctrl+G)で以下を実行:
Application.EnableEvents = True
エラー処理と EnableEvents の安全な組み合わせ方は エラー処理(On Error)で止まらないマクロを作る方法 を参照。
Q5: BeforeClose で「保存しますか?」のダイアログを自作したい
Workbook_BeforeClose の中で ThisWorkbook.Saved プロパティをチェックする:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
If Not ThisWorkbook.Saved Then
Dim ans As VbMsgBoxResult
ans = MsgBox("変更が保存されていません。保存しますか?", _
vbYesNoCancel + vbExclamation)
Select Case ans
Case vbYes: ThisWorkbook.Save
Case vbCancel: Cancel = True '← 閉じるのをキャンセル
' vbNo → 保存せず閉じる
End Select
End If
End Sub
ブックの保存と閉じる操作をまとめて自動化したい場合は ブックを保存して閉じる方法 も参照。
—
まとめ
- Workbook_Open: ブックを開いたときに自動実行。起動時のデータ更新やメッセージ表示に使う
- Workbook_BeforeSave: 保存前に自動チェック。空欄チェックやバックアップ作成に使う
- Workbook_BeforeClose: 閉じる前に自動処理。ログ記録や保存確認に使う
- 貼り付け場所は ThisWorkbook モジュール(標準モジュールでは動かない)
- EnableEvents の制御を忘れないこと(On Error GoTo で True に戻すのが安全)
関連記事
- セルの値が変わったら自動実行(Worksheet_Change) — セル変更トリガーとの使い分け
- 指定時刻にマクロを自動実行する方法 — 時刻トリガーとの使い分け
- ブックを自動保存する方法 — 保存処理の発展
- ブックを保存して閉じる方法 — 閉じる操作の自動化
- エラー処理(On Error)で止まらないマクロを作る方法 — EnableEventsの安全な制御
—
次にやりたくなること
- 指定時刻にマクロを自動実行する方法: ブックを開いたときだけでなく、毎日決まった時刻に自動実行したい場合
- ブックを保存して閉じる方法: イベント処理と組み合わせて、保存→閉じるの一連操作を完全自動化したい場合
- セルの入力値をVBAでチェック・制限する方法: Worksheet_Changeイベントでセル入力時のバリデーションを行いたい場合


コメント