こんにちは!MS Projectの自動化の世界へようこそ。
普段Excel VBAを使っている方にとって、Projectのオブジェクトモデルは少し独特で、最初は戸惑うこともあるかもしれません。
でも、安心してください。ここをクリアすれば、Project VBAの基本はバッチリですよ!
今回は、実務で本当によくある「特定のリソース(担当者)に、個別の休暇や例外的な稼働日を設定する」というテーマを深掘りしていきましょう。マクロの記録だけでは絶対にたどり着けない、CalendarとExceptionの裏側を優しく、かつ本質的に解説していきます。
—
1. Project VBAの心臓部:ResourceとCalendarの関係
MS Projectでは、人や機械といった「リソース」に、それぞれ稼働スケジュール(カレンダー)が紐付いています。
全体共通の「標準」カレンダーとは別に、「Aさんは来週の月曜日に有給休暇を取る」「Bさんは水曜日の午後だけ特別に稼働する」といった個別の上書きを行うには、`Resource` オブジェクトから `Calendar` オブジェクトへアクセスし、その中の `Exceptions`(例外日) を操作する必要があります。
構造を図解すると、このような階層になっています。
Application
└─ Project (ActiveProject)
├─ Resources (リソース群)
│ └─ Resource (特定の担当者)
│ └─ BaseCalendar / Calendar (リソース個別のカレンダー)
│ └─ Exceptions (例外日・休暇のコレクション)
│ └─ Exception (個別の休暇データ)
- – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
※注意:実はResourceから直接Calendarをいじるには、少しコツが要ります!
陥りやすい罠:Resource.Calendarは存在しない?
Excel VBAのノリで `ActiveProject.Resources(“山田 太郎”).Calendar` のように書きたくなりますが、実はResourceオブジェクトに直接カレンダーを返すプロパティはありません。
正解は、リソース自体のベースカレンダーを取得し、それを操作する、もしくはプロジェクト全体のカレンダーコレクションから名前を特定して操作アプローチをとります。今回は、実務で最も確実な「リソース固有のベースカレンダー(またはプロジェクトカレンダーのオーバーライド)」を操作するアプローチを取り入れます。
—
2. 実践!特定のリソースに休暇をVBAで動的に追加するコード
それでは、開発現場でそのままコピペして使える実用的なコードを見ていきましょう。
今回は、「山田 太郎」というリソースに対して、特定の期間(例:来週の月曜日)を休日(例外日)として追加するプログラムです。
Sub OverrideResourceCalendar()
‘ =========================================================================
‘ 処理概要: 特定のリソースの稼働カレンダーに例外日(休暇)を追加する
‘ 対象読者: マクロの記録から脱却し、実務で自動化を進めたい方
‘ =========================================================================
On Error GoTo ErrorHandler
Dim targetResourceName As String
targetResourceName = “山田 太郎” ‘ ここに目的の担当者名を設定
Dim targetRes As Resource
Dim found As Boolean
found = False
‘ 1. アクティブプロジェクトから対象のリソースを探索
For Each targetRes In ActiveProject.Resources
‘ リソースが空白行でないか、名前が一致するかチェック
If Not targetRes Is Nothing Then
If targetRes.Name = targetResourceName Then
found = True
Exit For
End If
End If
Next targetRes
If Not found = True Then
MsgBox “リソース「” & targetResourceName & “」が見つかりませんでした。”, vbExclamation, “エラー”
Exit Sub
End If
‘ 2. リソースに割り当てられているカレンダー名を取得
‘ ※Projectでは、リソース個別にカレンダーを持つ場合、プロジェクトのベースカレンダーを拡張・参照します
Dim calName As String
calName = targetRes.Calendar.Name
‘ デバッグ確認用
Debug.Print “対象リソース: ” & targetRes.Name & ” / カレンダー名: ” & calName
‘ 3. カレンダーオブジェクトを取得し、例外日(Exception)を追加
Dim targetCal As Calendar
Set targetCal = ActiveProject.BaseCalendars(calName)
‘ 【重要】Exceptionを追加する際の注意点
‘ すでに同じ日付に例外が設定されている場合のエラーを防ぐため、
‘ 追加前に一度クリアするか、重複チェックを入れるのが実務の作法です。
Dim exStart As Date
Dim exFinish As Date
exStart = DateAdd(“d”, 1, Date) ‘ 例として「明日」を起点に設定
exFinish = exStart ‘ 1日だけの休暇なら開始と終了を同じにする
‘ Exceptionsコレクションに新しい休暇を追加
‘ 引数: Name(名前), Start(開始日), Finish(終了日)
targetCal.Exceptions.Add Name:=”リフレッシュ休暇”, _
Start:=exStart, _
Finish:=exFinish, _
Type:=pjExceptionRecurrenceDaily ‘ 日単位の例外
MsgBox “「” & targetResourceName & “」のカレンダーに例外日を設定しました!”, vbInformation, “成功”
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “システムエラー”
End Sub
—
3. コードのポイントと、初心者がハマりやすい「落とし穴」
上記のコードには、Project VBAを実務で使う上で絶対に知っておくべき「3つの知見」が詰まっています。
① `Nothing` 判定の厳密さ
Excelのセルのように「空っぽ」の概念が、Projectのリソーステーブルにも存在します。`For Each targetRes In ActiveProject.Resources` でループを回す際、途中に空行が含まれていると `targetRes.Name` を参照した瞬間に実行時エラー(オブジェクト変数が設定されていません)になります。
そのため、`If Not targetRes Is Nothing Then` というガード節が必須です。
② カレンダーのスコープ(BaseCalendarとResource)
MS Projectのカレンダーには、全社・プロジェクト共通の BaseCalendar(基本カレンダー) と、リソース個別に紐づくものがあります。
今回のコードでは `ActiveProject.BaseCalendars(calName)` を使って大本のカレンダーに例外を追加しています。そのため、もしそのカレンダーを他のリソースと共有している場合、他の人のスケジュールにも影響が出る点に注意してください。
完全な個人専用カレンダーにしたい場合は、事前に `BaseCalendars.Add` で新規カレンダーを作成し、それをリソースに割り当てるという一手間が必要になります。
③ 日付操作(DateAddの活用)
ハードコーディングで `”2023/12/01″` のように日付を指定すると、マクロを走らせるたびにコードを書き換える羽目になります。
`DateAdd` 関数や `Date` 関数を組み合わせて、「今日から〇日後」といった動的な日付計算を組み込むのが、実務で使える自動化エンジニアのテクニックです。
—
おわりに
いかがでしたでしょうか?
「Resourceからカレンダーを辿り、Exceptionsコレクションにアクセスする」という一連の流れが掴めれば、大量のメンバーのシフト管理や、急なアサイン変更に伴うスケジュール調整も、一瞬でVBAにやらせることができます。
ここをクリアできれば、もう「マクロの記録の奴隷」ではありません。あなた自身の意志でProjectを意のままに操る、立派な自動化エンジニアです。
次回のテーマでも、さらに現場で使える実践的なノリと知見をお届けします。お楽しみに!
