【入門編】リソースの「カレンダー例外」をOutlookの共有予定表から自動インポートする – Project VBA解析バイブル

スポンサーリンク

伝説的なチーフアーキテクトがお届けする、極限のProject VBA術へようこそ。

今回は、日々のプロジェクト運営で多くの担当者が頭を悩ませる「リソースのカレンダー例外」を、Microsoft Outlookの共有予定表から自動でインポートするという、まさに業務自動化の真髄に触れるテーマを深く掘り下げていきます。

「マクロの記録」から一歩踏み出し、オブジェクトのライフサイクルとパフォーマンスの重みを理解し、魂のこもったコードを書くための知見を、優しく、しかし本質を突く形で伝授しましょう。

プロジェクトの命運を握る「リソースカレンダー」の極意

プロジェクト管理において、リソース(メンバー)の稼働状況は、まさにプロジェクトの血流とも言える重要な要素です。特に、メンバーの休暇や研修といった「カレンダー例外」は、計画の遅延やコスト超過に直結するため、正確かつタイムリーな管理が求められます。

手動でOutlookの予定表を確認し、Projectのリソースカレンダーに一つ一つ入力する作業は、想像を絶する手間と時間を要します。しかし、この非効率な作業は、VBAの力をもってすれば、魔法のように自動化できるのです。

「Outlookの共有予定表からProjectに休暇を自動インポートする」――これは単なるデータ連携ではありません。それは、リアルタイムな情報に基づいた意思決定を可能にし、プロジェクトの予見性を飛躍的に高める、まさしく「極限の知見」なのです。

Projectのリソースカレンダーと「例外」の構造

まず、Projectがリソースの稼働状況をどのように管理しているか、その基本構造を理解することから始めましょう。

Projectでは、各リソースに固有の「カレンダー」が割り当てられています。このカレンダーには、週ごとの稼働時間や祝日などの「基本情報」に加えて、特定の期間だけ稼働状況が異なる「例外」を登録できます。

VBAからこれらの情報にアクセスするには、以下のようなオブジェクト階層を辿ります。

  • `Application` (Projectアプリケーション全体)
  • `ActiveProject` (現在開いているプロジェクト)
  • `Resources` (プロジェクト内の全リソースのコレクション)
  • `Resource` (特定のリソース)
  • `Calendar` (リソースに割り当てられたカレンダー)
  • `Exceptions` (カレンダーに設定された例外のコレクション)
  • `Exception` (個々の例外設定)

今回のテーマである「休暇」は、この `Exception` オブジェクトとして Project に登録されることになります。`Exception` オブジェクトは、以下の重要なプロパティを持ちます。

  • `Start`: 例外期間の開始日
  • `Finish`: 例外期間の終了日
  • `Type`: 例外の種類(例: `pjExceptionTypeDaily` で「稼働日ではない」を示す)
  • `Name`: 例外の名前(例: 「夏季休暇」「研修」など)

この構造を理解すれば、VBAでカレンダー例外を自由自在に操る道が開けます。

なぜOutlook連携が「極限の知見」なのか?

私たちが目指すのは、単なるデータ転記ではありません。プロジェクト管理における真の課題は、「情報の鮮度」と「シングルソースオブトゥルース(信頼できる唯一の情報源)」の確立にあります。

チームメンバーの休暇情報は、通常、Outlookの共有予定表に登録されることが多いでしょう。これをProjectに手動で転記する行為は、二重入力であり、情報の不整合や陳腐化のリスクを常に抱えます。

Outlook連携は、この課題を根本から解決します。

1. リアルタイム性: Outlookの予定が更新されれば、Projectもそれに追随する仕組みを構築できます。
2. シングルソースオブトゥルース: 休暇情報の登録はOutlookに一元化され、Projectはそれを参照する形になるため、情報の信頼性が向上します。
3. ヒューマンエラーの削減: 手動入力に伴うミスを排除し、正確なプロジェクト計画を支えます。

この連携を実現するためには、VBAからOutlookのオブジェクトモデルを理解し、操作する必要があります。

VBAからOutlookを操る基本

Project VBAからOutlookを操作する場合も、Projectの場合と同様にオブジェクト階層を辿ります。

  • `Outlook.Application` (Outlookアプリケーション全体)
  • `Outlook.NameSpace` (MAPIセッションへのアクセスポイント)
  • `Outlook.Recipient` (特定のOutlookユーザー)
  • `Outlook.MAPIFolder` (受信トレイ、送信済みアイテム、予定表などのフォルダ)
  • `Items` (フォルダ内のアイテムのコレクション)
  • `Outlook.AppointmentItem` (個々の予定アイテム)

特に重要なのが、`GetSharedDefaultFolder` メソッドです。これにより、指定したユーザーの共有予定表にアクセスできるようになります。

実装ステップの全体像

それでは、具体的な実装のステップを見ていきましょう。
大きく分けて、以下の流れで処理を進めます。

1. 参照設定の追加: Project VBAからOutlookのオブジェクトモデルを利用できるよう設定します。
2. リソースとOutlookユーザーの特定: どのリソースのカレンダーを更新し、どのOutlookユーザーの予定表を参照するかを決めます。
3. Outlook予定表からのイベント読み込み: 指定されたユーザーの予定表から、休暇と見なせるイベント(終日イベントなど)を抽出します。
4. Projectカレンダーへの例外登録: 読み込んだイベント情報に基づき、Projectのリソースカレンダーに例外を追加・更新します。
5. 後処理: オブジェクトの解放や画面更新の復元などを行います。

この一連の流れを、具体的なコードとともに見ていきましょう。

極限の知見を宿すコードの実装

ここからは、実際にProject VBAで動作するコードを解説していきます。まずは、この自動化を実現するために不可欠な「参照設定」から始めましょう。

ステップ1: 参照設定の追加

VBAからProjectやOutlookといった外部アプリケーションのオブジェクトを操作するには、そのアプリケーションのオブジェクトライブラリへの「参照設定」が必要です。これは、VBAに「こういうオブジェクトがあるよ」と教えてあげるようなものです。

1. Projectを開き、`Alt + F11` を押してVBAエディタを起動します。
2. VBAエディタのメニューバーから `ツール(T)` -> `参照設定(R)…` を選択します。
3. 表示されるダイアログボックスで、以下のライブラリにチェックを入れます。

  • `Microsoft Project 16.0 Object Library` (Projectのバージョンによって数字が異なる場合があります)
  • `Microsoft Outlook 16.0 Object Library` (Outlookのバージョンによって数字が異なる場合があります)

![Project VBA 参照設定](https://example.com/project_vba_references.png)
(注: 上記はイメージです。実際にはご自身の環境で参照設定ダイアログをご確認ください。)

チェックを入れたら `OK` をクリックしてダイアログを閉じます。これで、Project VBAからProjectとOutlookのオブジェクトを操作する準備が整いました。

ステップ2: コードの全体像とカスタマイズポイント

それでは、具体的なコードを見ていきましょう。今回は、特定のProjectリソース(例:「山田 太郎」)の休暇を、Outlookの共有予定表から読み込み、Projectのカレンダー例外として登録するスクリプトです。

Option Explicit ‘ 変数の宣言を強制する。これぞ、堅牢なコードの第一歩!

Sub ImportOutlookVacationsToProject()
‘ 変数宣言: オブジェクトの型を明確に指定することで、コンパイル時チェックが働き、
‘ パフォーマンスも向上します。これぞ、チーフアーキテクトのこだわり!
Dim projApp As MSProject.Application
Dim projRes As MSProject.Resource
Dim projCalendar As MSProject.Calendar
Dim projExcept As MSProject.Exception
Dim olApp As Outlook.Application
Dim olNs As Outlook.NameSpace
Dim olRecipient As Outlook.Recipient
Dim olFolder As Outlook.MAPIFolder
Dim olItem As Object ‘ Outlook.AppointmentItem 以外のアイテムも考慮し、汎用的にObject型
Dim olAppt As Outlook.AppointmentItem
Dim dtStart As Date, dtEnd As Date
Dim bExceptionExists As Boolean ‘ 既存の例外が存在するかどうかのフラグ

‘ ■■■ 最重要: カスタマイズポイント!ここをあなたの環境に合わせて変更してください ■■■
‘ どのProjectリソースのカレンダーを更新しますか?
‘ ここには、Projectファイルに登録されているリソースの名前を正確に入力してください。
Const TARGET_RESOURCE_NAME As String = “山田 太郎”

‘ どのOutlookユーザーの共有予定表から休暇を読み込みますか?
‘ 通常はTARGET_RESOURCE_NAMEと同じ名前であることが多いですが、異なる場合は変更してください。
‘ 例: “taro.yamada@yourcompany.com” のようにメールアドレスでも指定可能です。
Const OUTLOOK_CALENDAR_OWNER As String = “山田 太郎”
‘ ■■■ カスタマイズポイントここまで ■■■

‘ 画面更新停止: 大量の処理を行う前に必ずこれを設定すること!
‘ これにより、VBAが画面を再描画する手間が省け、劇的に処理速度が向上します。
‘ これこそが、パフォーマンスチューニングの基本中の基本、極限の知見です。
Application.ScreenUpdating = False

‘ エラーハンドリング: 予期せぬエラーが発生しても、プログラムが停止しないようにします。
‘ ユーザーフレンドリーな自動化には必須の要素です。
On Error GoTo ErrorHandler

‘ Projectアプリケーションオブジェクトを取得
‘ このマクロがProject内で実行されるため、ApplicationはProject自身を指します。
Set projApp = Application

‘ Outlookアプリケーションオブジェクトを取得
‘ Outlookが起動していなければ新規作成し、起動していれば既存のインスタンスを取得します。
Set olApp = New Outlook.Application
‘ MAPIネームスペースを取得: Outlookの各種フォルダにアクセスするために必要です。
Set olNs = olApp.GetNamespace(“MAPI”)

‘ ————————————————————————–
‘ 1. Projectリソースの特定
‘ ————————————————————————–
Debug.Print “Projectリソース ‘” & TARGET_RESOURCE_NAME & “‘ を検索中…”
For Each projRes In projApp.ActiveProject.Resources
If projRes.Name = TARGET_RESOURCE_NAME Then
Set projCalendar = projRes.Calendar ‘ リソースのカレンダーを取得
Exit For ‘ 見つかったらループを抜ける
End If
Next projRes

‘ リソースが見つからなかった場合の処理
If projCalendar Is Nothing Then
MsgBox “指定されたProjectリソースが見つかりません: ” & TARGET_RESOURCE_NAME & vbCrLf & _
“Projectファイルにリソースが存在するか、名前が正しいか確認してください。”, vbCritical
GoTo CleanUp ‘ 後処理へ
End If
Debug.Print “Projectリソースとカレンダーを特定しました。”

‘ ————————————————————————–
‘ 2. Outlook共有予定表の特定
‘ ————————————————————————–
Debug.Print “Outlookユーザー ‘” & OUTLOOK_CALENDAR_OWNER & “‘ の予定表を検索中…”
‘ OutlookユーザーをRecipientオブジェクトとして作成し、解決します。
Set olRecipient = olNs.CreateRecipient(OUTLOOK_CALENDAR_OWNER)
olRecipient.Resolve ‘ 指定された名前を実際のOutlookユーザー(メールアドレスなど)に解決します。

‘ ユーザーが見つからなかった場合の処理
If Not olRecipient.Resolved Then
MsgBox “Outlookユーザーが見つかりません: ” & OUTLOOK_CALENDAR_OWNER & vbCrLf & _
“Outlookのアドレス帳にユーザーが存在するか、名前が正しいか確認してください。”, vbCritical
GoTo CleanUp ‘ 後処理へ
End If

‘ 共有予定表を取得 (olFolderCalendar は Outlook の定数で予定表フォルダを示します)
Set olFolder = olNs.GetSharedDefaultFolder(olRecipient, olFolderCalendar)
If olFolder Is Nothing Then
MsgBox “Outlookユーザー ‘” & OUTLOOK_CALENDAR_OWNER & “‘ の共有予定表にアクセスできませんでした。” & vbCrLf & _
“アクセス権限があるか確認してください。”, vbCritical
GoTo CleanUp ‘ 後処理へ
End If
Debug.Print “Outlook共有予定表を特定しました。”

‘ ————————————————————————–
‘ 3. Outlook予定表からのイベント読み込みとProjectカレンダーへの例外登録
‘ ————————————————————————–
Debug.Print “Outlook予定表から休暇イベントを読み込み、Projectカレンダーに反映します。”

‘ Outlookのアイテムコレクションをループして、個々の予定を取得します。
‘ Items.Restrict メソッドを使えば、特定の期間や件名でフィルタリングできますが、
‘ 今回はシンプルにすべてのアイテムをチェックします。データ量が多い場合は検討しましょう。
For Each olItem In olFolder.Items
‘ オブジェクトがAppointmentItem(予定アイテム)であるか確認します。
If TypeOf olItem Is Outlook.AppointmentItem Then
Set olAppt = olItem

‘ 終日イベント(AllDayEvent)のみを「休暇」として対象とします。
‘ 定期的な予定(RecurrencePattern)は複雑なため、今回は考慮していません。
‘ 実装をシンプルに保つため、単発の終日イベントに限定します。
If olAppt.AllDayEvent Then
‘ Outlookの終日イベントは、終了日が翌日の0時になるため、
‘ Projectのカレンダー例外に合わせるために1日引いて調整します。
dtStart = olAppt.Start
dtEnd = olAppt.End – 1 ‘ 例: 1/1の終日イベントなら、Start=1/1 0:00, End=1/2 0:00。
‘ Projectでは1/1 0:00 – 1/1 23:59:59 としたい。

bExceptionExists = False
‘ 既存のProjectカレンダー例外をチェックし、重複登録を避けます。
‘ ここが「極限の知見」のポイントの一つ。単純な追加だけでなく、既存の情報を考慮する。
For Each projExcept In projCalendar.Exceptions
‘ 開始日と終了日が完全に一致する例外が存在するかどうかをチェックします。
If projExcept.Start = dtStart And projExcept.Finish = dtEnd Then
‘ 既存の例外が見つかった場合は、フラグを立ててループを抜けます。
‘ 今回は、既にあれば何もしない(スキップ)方針です。
‘ もしOutlookの予定変更をProjectに反映したい場合は、
‘ ここで既存の例外を削除してから再登録する、といったロジックが必要になります。
‘ (その場合は、OutlookのEntryIDなどをProjectの例外名に含めておくと良いでしょう)
bExceptionExists = True
Exit For
End If
Next projExcept

If Not bExceptionExists Then
‘ 既存の例外がなければ、新しい例外として追加します。
‘ Type:=pjExceptionTypeDaily は、その期間が稼働日ではないことを示します。
projCalendar.Exceptions.Add _
Type:=pjExceptionTypeDaily, _
Start:=dtStart, _
Finish:=dtEnd, _
Name:=olAppt.Subject & ” (Outlook)” ‘ Outlookの件名と識別子を名前に

Debug.Print ” -> 追加: ” & olAppt.Subject & ” (” & Format(dtStart, “yyyy/mm/dd”) & ” – ” & Format(dtEnd, “yyyy/mm/dd”) & “)”
Else
Debug.Print ” -> スキップ(既存): ” & olAppt.Subject & ” (” & Format(dtStart, “yyyy/mm/dd”) & ” – ” & Format(dtEnd, “yyyy/mm/dd”) & “)”
End If
End If
End If
Next olItem

MsgBox “リソースカレンダーへのOutlook休暇のインポートが完了しました。”, vbInformation

CleanUp:
‘ ————————————————————————–
‘ 後処理: オブジェクトの解放と画面更新の復元
‘ ————————————————————————–
‘ オブジェクトの解放: 参照を解除することで、メモリリークを防ぎ、リソースを適切に開放します。
‘ Set obj = Nothing の順序は、上位オブジェクトからではなく、下位オブジェクトから解放するのが一般的です。
‘ これも、オブジェクトのライフサイクルを意識したチーフアーキテクトのこだわりです。
Set projExcept = Nothing
Set projCalendar = Nothing
Set projRes = Nothing
Set projApp = Nothing
Set olAppt = Nothing
Set olItem = Nothing
Set olFolder = Nothing
Set olRecipient = Nothing
Set olNs = Nothing
‘ Outlookアプリケーションオブジェクトは、マクロ終了時に自動で終了しない場合があるため、
‘ ここで明示的にQuitを呼び出すことで、確実に終了させることができます。
If Not olApp Is Nothing Then
olApp.Quit
Set olApp = Nothing
End If

‘ 画面更新を元に戻す: エラーで中断した場合でも、忘れずにTrueに戻すことが重要です。
Application.ScreenUpdating = True
Exit Sub ‘ エラーハンドラへの分岐を避ける

ErrorHandler:
‘ エラーメッセージを表示し、どこでエラーが発生したかをユーザーに伝えます。
MsgBox “処理中にエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical
Resume CleanUp ‘ エラー発生後も、後処理は必ず実行するようにします。
End Sub

コード解説と「極限の知見」のポイント

  • `Option Explicit`: コードの冒頭にこれを記述すると、全ての変数を宣言しないとコンパイルエラーになります。一見面倒に思えますが、タイプミスによるバグを防ぎ、コードの可読性と保守性を高める「極限の知見」です。
  • 型宣言の重要性: `Dim projRes As MSProject.Resource` のように、変数の型を明示的に宣言することで、VBAは事前にメモリを確保し、コンパイル時にエラーをチェックできるようになります。これにより、実行時エラーを減らし、コードのパフォーマンスも向上します。
  • `Application.ScreenUpdating = False`: これを処理の最初に設定し、終了時(エラー時も含めて)`True` に戻すのは、大量のオブジェクト操作を行う際のパフォーマンス最適化の鉄則です。画面の再描画を抑止することで、処理速度が劇的に向上します。
  • エラーハンドリング (`On Error GoTo ErrorHandler`): 業務自動化ツールは、エラーで停止しては意味がありません。予期せぬ事態に備え、エラーが発生しても適切に処理を終了し、ユーザーに状況を伝える仕組みは必須です。`Resume CleanUp` で必ず後処理を通るようにしているのもポイントです。
  • Outlookオブジェクトの解放 (`Set obj = Nothing`): オブジェクトの参照を解放し、メモリリークを防ぐための重要なステップです。特にOutlookは、明示的に `olApp.Quit` しないとバックグラウンドで起動し続けることがあるため、注意が必要です。
  • `GetSharedDefaultFolder`: 共有予定表にアクセスするための肝となるメソッドです。`olRecipient` オブジェクトを介して、特定のユーザーのデフォルトフォルダ(ここでは予定表)を取得します。
  • 終日イベントの扱い: Outlookの終日イベントは、`Start` が開始日の0時、`End` が終了日の翌日の0時となります。Projectのカレンダー例外と期間を合わせるため、`dtEnd = olAppt.End – 1` と調整しています。
  • 既存例外の重複チェック: これが今回の「極限の知見」の最も重要な部分の一つです。Projectにすでに登録されている例外と、Outlookから読み込んだ休暇が重複しないよう、開始日と終了日を比較しています。
  • 今回のコードでは、重複する例外が見つかった場合は「スキップ」しています。
  • さらに一歩進むなら: Outlookの予定が変更された場合、Projectの例外も更新する必要があります。その場合、Projectの例外の `Name` プロパティにOutlookの `EntryID` などのユニークな識別子を埋め込んでおき、それをキーにして既存の例外を `Delete` してから、最新の情報で `Add` し直す、というロジックが必要になります。これは、より高度な自動化への扉を開くでしょう。
  • `pjExceptionTypeDaily`: Projectのカレンダー例外の種類を指定する定数です。この場合、「指定された期間は稼働日ではない」とProjectに伝えます。

よくある落とし穴と解決策

1. 参照設定の忘れ

  • 症状: `ユーザー定義型は定義されていません` や `コンパイルエラー: オブジェクトが見つかりません` などのエラーが発生します。
  • 解決策: 上記「ステップ1: 参照設定の追加」に戻り、`Microsoft Project Object Library` と `Microsoft Outlook Object Library` にチェックが入っていることを確認してください。

2. Outlookセキュリティ警告

  • 症状: Outlookオブジェクトモデルにアクセスする際に、「プログラムがOutlookにアクセスしようとしています」という警告ダイアログが表示されることがあります。
  • 解決策:
  • これはOutlookのセキュリティ機能によるものです。根本的な解決策としては、アンチウイルスソフトの設定や、Exchangeサーバー側の設定変更が必要になる場合があります(管理者権限が必要)。
  • 個人利用やテスト環境であれば、Outlookの「ファイル」->「オプション」->「トラストセンター」->「トラストセンターの設定」->「プログラムによるアクセス」で設定を変更できる場合がありますが、セキュリティリスクを伴うため推奨されません。
  • 実運用では、Office JS APIやGraph APIなど、モダンなAPIを利用する方向を検討することも重要です。

3. リソース名とOutlookユーザー名の不一致

  • 症状: 「指定されたProjectリソースが見つかりません」や「Outlookユーザーが見つかりません」というメッセージが表示されます。
  • 解決策: `TARGET_RESOURCE_NAME` と `OUTLOOK_CALENDAR_OWNER` の定数が、Projectのリソース名およびOutlookユーザー名(またはメールアドレス)と完全に一致していることを確認してください。大文字・小文字、全角・半角スペースなども厳密にチェックが必要です。

4. Outlook共有予定表へのアクセス権限不足

  • 症状: 「共有予定表にアクセスできませんでした」というメッセージが表示されます。
  • 解決策: Outlookユーザーが、参照しようとしている共有予定表に対する「閲覧者」以上のアクセス権限を持っているかを確認してください。通常、共有予定表の所有者に設定してもらう必要があります。

5. パフォーマンス問題

  • 症状: 処理に時間がかかりすぎる。
  • 解決策:
  • `Application.ScreenUpdating = False` を必ず設定する。
  • Outlookの `Items.Restrict` メソッドを使って、読み込む予定の数を絞り込む(例: `olFolder.Items.Restrict(“[Start] >= “”” & Format(Date, “yyyy/mm/dd”) & “”””)` のように、今日以降の予定のみを対象にする)。
  • `Debug.Print` はデバッグ中は便利ですが、本番運用時はコメントアウトするか削除して、ログファイルに出力するなどの方法に切り替えることを検討しましょう。

さらに一歩踏み込むためのヒント

今回のコードは、Project VBAとOutlook連携の基本的な構造と、「極限の知見」たるパフォーマンス、堅牢性、そして拡張性への意識を盛り込んだものです。ここをクリアすれば、Project VBAの基本はバッチリですよ。

しかし、真の業務自動化エンジニアは、常に「もっと良くするには?」と考え続けます。

  • リソースとOutlookユーザーの紐付け強化:

Projectのリソースのカスタムフィールドに、対応するOutlookユーザーのメールアドレスを登録しておけば、コード内でリソース名からOutlookユーザーを動的に特定できるようになります。これにより、`TARGET_RESOURCE_NAME` や `OUTLOOK_CALENDAR_OWNER` をハードコーディングする手間が省け、汎用性が高まります。

  • 特定のカテゴリの予定のみをインポート:

Outlookの予定には「カテゴリ」を設定できます。「休暇」「研修」など、特定のカテゴリが付与された予定のみをProjectにインポートするように、Outlookの `Items.Restrict` メソッドや `AppointmentItem.Categories` プロパティを使ってフィルタリングすることで、より柔軟な運用が可能になります。

  • Outlookの定期的な予定の処理:

今回のコードでは終日イベントのみを対象としましたが、Outlookの定期的な予定(毎週会議など)をProjectのリソースカレンダーに反映させたい場合は、`AppointmentItem.GetRecurrencePattern` メソッドを使って繰り返しパターンを解析し、Projectの `Calendar.Exceptions.Add` メソッドの `Type` プロパティで `pjExceptionTypeWeekly` や `pjExceptionTypeMonthly` を指定する必要があります。これは高度なテーマですが、挑戦する価値はあります。

  • VBAからOffice JS API / Microsoft Graph APIへ:

VBAは強力なツールですが、セキュリティの制約やモダンなWebサービスとの連携には限界もあります。将来的には、Office JS API(Officeアドイン)や Microsoft Graph API を利用して、クラウドベースの自動化やよりセキュアな連携を検討することも、チーフアーキテクトとしての視野には入れておきたいところです。

まとめ

Project VBAとOutlookを連携させ、リソースのカレンダー例外を自動インポートするこの仕組みは、手作業による煩雑な管理から解放し、プロジェクトマネージャーがより本質的な業務に集中できる時間をもたらします。

今回学んだのは、単なるVBAの書き方だけではありません。オブジェクトのライフサイクル、パフォーマンスへの配慮、堅牢なエラーハンドリング、そして将来への拡張性を見据えた設計思想。これこそが、世界最高峰の業務自動化エンジニアが持つ「極限の知見」なのです。

この知識を武器に、あなたのプロジェクト管理を次のレベルへと引き上げてください。
「ここをクリアすれば、Project VBAの基本はバッチリですよ。さあ、次の自動化の課題に挑戦しましょう!」

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