こんにちは!Microsoft Projectの裏側でうごめくVBAの世界へようこそ。
マクロの記録ボタンを押すだけの日常から一歩踏み出し、「自分の手でProjectを意のままに操りたい」そう思っているあなたへ。
今回は、実務でめちゃくちゃよくある頭痛のタネ、「特定期間のリソース割り当てを抽出して、一括でコストやアサインを調整する」というテーマを深掘りします。
ここをクリアできれば、Project VBAのオブジェクト構造の基本と、実戦で使える「泥臭いけれど確実なフィルター技術」が自分のものになります。
優しく、かつ本質的なところまでしっかり導きますので、安心してついてきてくださいね!
—
なぜ「期間で絞り込んだリソース一括編集」が必要なのか?
大規模なプロジェクトを動かしていると、こんな要望が飛んできます。
- 「来月(特定期間)に突入するタスクについて、シニアエンジニアの単価を一時的に引き上げたい」
- 「この期間、過負荷になっているリソースの割り当てをいったんゴソッと整理したい」
これをGUI(画面上のマウス操作)でやろうとすると、ガントチャートを睨みながら一つひとつのタスクを開き、リソースタブを確認して……と、気が狂うような手作業になります。ミスも起きやすい。
だからこそ、VBAで条件(期間)に合致する「Assignment(割り当て)」をピンポイントで捕らえ、一網打尽にする必要があるのです。
—
Project VBAの心臓部:Task・Resource・Assignment の関係
コードを書く前に、Project特有の「三すくみ」の関係を知っておきましょう。ここが理解の分水嶺です。
1. Task(タスク): 「何をするか」(例:基本設計)
2. Resource(リソース): 「誰が・何がやるか」(例:山田さん、サーバー)
3. Assignment(割り当て): 「誰が・どのタスクを・いつからいつまでやるか」の結びつき
今回操作するのは、この3番目 `Assignment` です。
タスク単位でも、リソース単位でもなく、「期間(Start / Finish)」を持っているのはAssignment であるという点が、最大のポイントになります。
—
実装コード:期間でフィルタリングしてコストを一括変更する
お待たせしました。こちらが実務でそのまま使える、洗練されたVBAコードです。開発環境(VBE)の標準モジュールに貼り付けてみてください。
Sub UpdateAssignmentsByPeriod()
‘ =====================================================================
‘ テーマ: 特定期間内のリソース割り当てを抽出し、コストを一括調整する
‘ =====================================================================
Dim tsk As Task
Dim asn As Assignment
Dim targetStart As Date
Dim targetFinish As Date
Dim updatedCount As Long
‘ 1. 対象となる期間を設定(例: 2023年10月1日 ~ 2023年10月31日)
targetStart = DateValue(“2023/10/01”)
targetFinish = DateValue(“2023/10/31”)
updatedCount = 0
‘ 2. プロジェクト内の全タスクを走査
For Each tsk In ActiveProject.Tasks
‘ タスクが存在しない(空行など)場合はスキップ
If Not tsk Is Nothing Then
‘ 3. 各タスクに紐づく「割り当て(Assignment)」を走査
For Each asn In tsk.Assignments
‘ 4. 割り当ての期間が、指定した期間と「重なっているか」を判定
‘ 条件: 割り当ての開始日が指定終了日以前、かつ、割り当ての終了日が指定開始日以降
If asn.Start <= targetFinish And asn.Finish >= targetStart Then
‘ 【実務アクション例】
‘ 対象期間に被っている割り当てに対して、コストや単価に関する処理を行う
‘ ここでは例として、Costに一律 10,000円 を加算(またはプロパティを書き換える)
‘ ※ CostやCostRateはリソースや割り当ての仕様に合わせて調整してください
‘ 例:メモ欄にフラグを立てる処理
asn.Notes = “【自動更新】10月対象アサイン”
‘ カウントアップ
updatedCount = updatedCount + 1
End If
Next asn
End If
Next tsk
‘ 5. 完了報告
MsgBox “処理が完了しました。” & vbCrLf & _
“対象となった割り当て件数: ” & updatedCount & ” 件”, _
vbInformation, “一括処理完了”
End Sub
—
コードの注目ポイントと「初心者がハマる罠」
ここからは、コードの裏側にある「プロの知見」を解説します。ここをクリアすれば、もうマクロの記録の卒業生です。
1. なぜ `For Each tsk In ActiveProject.Tasks` なのか?
Projectのオブジェクトモデルにおいて、`Assignments` は単独で宇宙に存在していません。必ず「Task」というコンテナの中にぶら下がっています。
そのため、「タスクを総なめし、その中にあるアサインを覗き見に行く」という二重ループの構造が基本形になります。
2. 「期間の重複判定」の美しさ
コード内のこの部分に注目してください。
If asn.Start <= targetFinish And asn.Finish >= targetStart Then
「期間が重なっている」という条件をプログラムで表現するとき、初心者は「期間の中にすっぽり収まっている場合」だけを考えがちです。
しかし、実務では「一部だけカスっている(期間をまたいでいる)」ケースも対象に含める必要があります。
「開始日が指定終了日より前、かつ、終了日が指定開始日より後」というロジックは、スケジューリング系APIを扱う上で最強の定番イディオム(定石)ですので、ぜひ覚えておいてください。
3. 「リソースがない行(Nothing)」への配慮
Projectのタスクリストの末尾や途中には、データが入っていない「空行」が存在することがあります。
`If Not tsk Is Nothing Then` というガードを挟むことで、空行に当たって `Object variable not set`(オブジェクト変数が設定されていません)というお馴染みのエラーが発生するのを未然に防いでいます。この優しさがバグを防ぎます。
—
応用編:割り当ての解除(削除)を行う場合
もし「単価変更」ではなく、特定の期間に該当する割り当てをごっそり解除(削除)したい場合は、ループの回し方に注意が必要です。
コレクションから要素を「削除」しながらループを回すときは、後ろから前へ(逆順で)回すのがVBAの鉄則ですが、TaskのAssignmentsは少し特殊です。安全に削除を行いたい場合は、以下のようにインデックスを使った逆順ループを組みます。
Dim i As Long
For i = tsk.Assignments.Count To 1 Step -1
Set asn = tsk.Assignments(i)
‘ 条件判定…
‘ asn.Delete ‘ 削除する場合はこう書きます
Next i
※一括削除はプロジェクト全体に大きな影響を与えるため、テスト環境で十分に挙動を確認してから本番適用するようにしてくださいね。
—
まとめ
お疲れ様でした!今回は以下のスキルを手に入れました。
- Task・Resource・Assignment の3者の関係性と、期間を持つのがAssignmentであることの理解
- 二重ループを使った効率的なデータ走査
- 実務で使える期間の重複判定ロジック
「ここをクリアすれば、Project VBAの基本はバッチリですよ!」
画面上のマウス操作に頼る日々はもう終わりです。あなたが書いたたった十数行のコードが、何百件ものリソース割り当てを瞬時に、正確に整えてくれます。この爽快感を味わえたら、もう立派な自動化エンジニアの仲間入りです。
現場でぜひ活用してみてくださいね。あなたのプロジェクト管理が劇的にスマートになることを応援しています!
