メタデータという「真実」を掴め:PowerPoint VBAによる属性駆動型ファイル仕分けの極意
業務の自動化において、ファイル名(Filename)を頼りに処理を行うのは、エンジニアとして「三流」の仕事だ。
ファイル名は人間が恣意的に変更できる、極めて不確実な変数に過ぎない。一方で、ファイルに埋め込まれたメタデータ(プロパティ)は、作成プロセスにおいてシステムやアプリケーションが刻印した「真実」である。
本稿では、開いている複数のプレゼンテーションから、特定の「作成者(Author)」プロパティを持つファイルのみを抽出し、別名で一括保存する、実務レベルの仕分けマクロを解説する。単なる「動くコード」ではなく、「壊れない、運用に耐えうる設計」を伝授しよう。
1. アーキテクトの視点:なぜ「ファイル名」ではなく「プロパティ」なのか
多くの初心者は「『プロジェクトA_最終版.pptx』というファイルを探す」コードを書こうとする。しかし、現場では「プロジェクトA_修正2.pptx」「プロジェクトA_20231010.pptx」といった、予測不能なファイル名が乱立する。
ここで、`BuiltInDocumentProperties` というオブジェクトの出番だ。
プレゼンテーションのプロパティ(作成者、タイトル、作成日時など)は、ファイル名がどう変わろうとも、そのファイルの本質的な属性として保持される。この「属性(Attribute)」をキーにロジックを組むことこそが、堅牢な自動化ツールの第一歩である。
2. 設計の要諦:プロダクションコードに求められる3つの規律
コードを書く前に、以下の設計原則を脳に刻んでほしい。
1. 副作用の最小化 (Side-Effect Minimization):
元のファイルを上書きしてはいけない。抽出したファイルは必ず「別名」または「別ディレクトリ」へ保存する。
2. 例外処理の徹底 (Robust Error Handling):
「保存先フォルダが存在しない」「ファイルが読み取り専用で開かれている」「プロパティが空である」といった、実務で必ず遭遇するエラーを想定せよ。
3. リソースの適切な管理 (Resource Management):
FileSystemObject (FSO) を活用し、パスの操作を文字列結合(`& “\” &`)ではなく、オブジェクトベースで行うこと。これはバグを劇的に減らす。
3. 実装:属性駆動型・一括抽出マクロ
以下に、プロフェッショナルな現場でそのまま通用するレベルのコードを示す。このコードは、`Microsoft Scripting Runtime` への参照設定を必要としない「レイトバインディング」方式を採用しており、配布時の環境依存トラブルを回避している。
Option Explicit
''' <summary>
''' 指定した作成者プロパティに一致するプレゼンテーションを抽出し、
''' 指定フォルダへ一括保存する。
''' </summary>
Public Sub ExtractPresentationsByAuthor()
' --- 設定エリア ---
Const TARGET_AUTHOR As String = "田中 太郎" ' 抽出したい作成者名
Const DEST_FOLDER As String = "C:\Output\Extracted_Files\" ' 保存先フォルダ
' ------------------
Dim pptApp As Application
Dim pres As Presentation
Dim fso As Object
Dim targetPath As String
Dim saveName As String
Dim successCount As Integer
Dim errorCount As Integer
Set pptApp = Application
Set fso = CreateObject("Scripting.FileSystemObject")
' 1. 保存先フォルダの存在確認と作成
On Error Resume Next
If Not fso.FolderExists(DEST_FOLDER) Then
' フォルダが存在しない場合は作成を試みる(親ディレクトリが必要な場合は別途設計が必要)
fso.CreateFolder DEST_FOLDER
If Err.Number <> 0 Then
MsgBox "保存先フォルダの作成に失敗しました。パスを確認してください。" & vbCrLf & DEST_FOLDER, vbCritical
Exit Sub
End If
End If
On Error GoTo 0
successCount = 0
errorCount = 0
' 2. 開いているすべてのプレゼンテーションを走査
' 注意: Presentationsコレクションは、現在PowerPointで開いている全てのインスタンスを指す
For Each pres In pptApp.Presentations
' プロパティの取得(エラー回避のため、BuiltInDocumentPropertiesを慎重に扱う)
Dim currentAuthor As String
On Error Resume Next
currentAuthor = pres.BuiltInDocumentProperties("Author")
On Error GoTo 0
' 3. 作成者の一致判定 (Trimで余計な空白を除去し、比較の精度を高める)
If Trim(currentAuthor) = Trim(TARGET_AUTHOR) Then
' 保存用ファイル名の生成 (元のファイル名 + _extracted)
' 拡張子を除いたファイル名を取得
Dim baseName As String
baseName = fso.GetBaseName(pres.FullName)
saveName = DEST_FOLDER & baseName & "_extracted.pptx"
' 4. 保存処理
On Error Resume Next
' SaveAsを使用する際は、元のファイルが「開いている」状態であることを考慮。
' コピーとして保存したい場合は、一度一時的に保存するか、SaveCopyAs的な挙動を設計する。
' ここでは、元のファイルへの影響を最小限にするため、SaveAsで別名保存を行う。
pres.SaveAs Filename:=saveName
If Err.Number = 0 Then
successCount = successCount + 1
Else
Debug.Print "Error saving: " & pres.Name & " - " & Err.Description
errorCount = errorCount + 1
End If
On Error GoTo 0
End If
Next pres
' 5. 結果報告
MsgBox "処理が完了しました。" & vbCrLf & vbCrLf & _
"抽出成功: " & successCount & " 件" & vbCrLf & _
"エラー: " & errorCount & " 件", vbInformation, "実行結果"
' オブジェクト解放
Set fso = Nothing
Set pptApp = Nothing
End Sub
4. 技術解説:なぜこのコードは「強い」のか
プロパティ取得における「防御的プログラミング」
`pres.BuiltInDocumentProperties(“Author”)` は、もしそのプロパティが存在しない特殊なファイルに対して実行されると、ランタイムエラーを吐いてマクロを停止させる。私はここで `On Error Resume Next` を局所的に使用し、プロパティの欠如を「異常事態」ではなく「単なるデータ不足」としてエレガントに処理している。
FileSystemObject (FSO) の採用
`Dir()` 関数は軽量だが、パスの操作(拡張子の除去、フォルダの存在確認など)において極めて脆弱だ。`fso.GetBaseName` を使うことで、ファイル名にドットが含まれる複雑なケースでも、正確にファイル名のみを抽出できる。これは、プロダクション環境における「予期せぬバグ」を防ぐための鉄則だ。
スケーラビリティへの示唆
もし、このツールを「開いているファイル」ではなく「特定のフォルダ内の全ファイル」に拡張したい場合は、`fso.GetFolder(path).Files` をループさせる構造に組み替えるだけでよい。ロジックの核(判定部分)を分離して考えているため、拡張性は極めて高い。
5. まとめ:自動化エンジニアへの道
初心者は「動くこと」をゴールにする。
プロフェッショナルは「壊れないこと」と「メンテナンスしやすさ」をゴールにする。
今回紹介したマクロは、単なるファイルのコピーではない。メタデータを信頼し、例外を制御し、オブジェクト指向的なアプローチでリソースを扱う。この思考プロセスこそが、君を単なる「マクロ使い」から「業務自動化エンジニア」へと引き上げる。
次に君が作るツールでは、ぜひこの「堅牢な設計」を実装してみてほしい。
