【テクニカル・上級編】プレゼンテーションの「読み取り専用推奨(ReadOnlyRecommended)」や「パスワード暗号化」をVBAで一括設定・解除するセキュリティツール – PowerPoint VBA解析バイブル

スポンサーリンク

PowerPoint要塞化計画:VBAによるセキュリティ属性の一括制御とオブジェクトライフサイクルの極限最適化

企業の機密情報、あるいは極秘裏に進められるM&Aのピッチデッキ。数千枚に及ぶプレゼンテーション資産が、野晒しのままファイルサーバーの海に漂っていないだろうか。
「読み取り専用推奨」の付与、そして強力な「オープンパスワード」の強制。これらを人的ミスに頼らず、一網打尽にプログラムで統御する。

今回は、単なる「動くコードの貼り付け」ではない。PowerPoint VBAのオブジェクトモデルの裏側でうごめくCOMの参照カウンタの摂理、そして実務の壁を打ち破るための極限の知見を、シニアエンジニアの視座から叩き込む。

1. オブジェクトモデルの深層と「見えないコスト」

PowerPoint VBAにおいて、`Application`, `Presentation`, `Slide` といったオブジェクト階層は、すべてCOM(Component Object Model)のラッパーに過ぎない。
特にファイルの一括操作やセキュリティ属性の書き換えを行う際、多くのプログラマが陥る致命的な罠が「参照のリーク(メモリリーク)」である。

‘ 【アンチパターン】これはいけない
Sub BadExample()
Dim pptApp As Object
Set pptApp = CreateObject(“PowerPoint.Application”)

‘ ループ内で次々とPresentationを開く
Dim wsh As Object: Set wsh = CreateObject(“WScript.Shell”)
‘ … 処理 …

‘ Applicationを放置、または不完全な解放
pptApp.Quit
Set pptApp = Nothing
End Sub

このコードの何が問題か。PowerPointの背後では重厚長大なプロセスが立ち上がり、`SaveAs` メソッドや暗号化処理を実行するたびに、メモリ空間上に不揮発性のCOMインスタンスの残骸が蓄積していく。
ループ処理の途中でエラーが発生すれば、バックグラウンドプロセス(`POWERPNT.EXE`)は永遠にタスクマネージャーに居座り続けることになる。

プロフェッショナルなアーキテクトは、「掴んだオブジェクトは必ずスコープの最短で解放し、例外発生時(Error Handler)のクリーンアップ経路を完全に担保する」

2. セキュリティ一括制御エンジン(実用VBAコード)

以下に提示するのは、指定したディレクトリ内のPowerPointファイル(`.pptx` / `.ppt`)を再帰的に走査し、「読み取り専用推奨(ReadOnlyRecommended)」の付与、および「オープンパスワード」の強制設定を一括で行う実用スクリプトである。

レガシーな `.ppt` 形式とモダンな `.pptx` 形式では、セキュリティ機構の内部挙動が異なる。それらを安全にハンドリングする堅牢な実装を見てほしい。

Option Explicit

‘ ==============================================================================
‘ プレゼンテーション要塞化ツール (PowerPoint Security Enforcer)
‘ Architecture Version: 4.2.0-Production
‘ ==============================================================================
Public Sub ExecuteSecurityEnforcement()
Dim targetDirectory As String
targetDirectory = “C:\ConfidentialData\PitchDecks\” ‘ 実際のパスに変更すること

If Dir(targetDirectory, vbDirectory) = “” Then
MsgBox “指定されたディレクトリが存在しません。”, vbCritical, “Critical Error”
Exit Sub
End If

Dim targetPassword As String
targetPassword = “SuperSecretPassword202X!” ‘ 適用する強力なオープンパスワード

‘ バックグラウンドでPowerPointを起動(UIを描画させないことでパフォーマンスを最大化)
Dim pptApp As PowerPoint.Application
Set pptApp = New PowerPoint.Application
pptApp.Visible = msoFalse
pptApp.DisplayAlerts = ppAlertsNone ‘ ダイアログによる処理停止を完全に排除

Dim processedCount As Long
processedCount = 0

On Error GoTo ErrorHandler

‘ ファイル走査の実行
Call ProcessDirectory(targetDirectory, pptApp, targetPassword, processedCount)

‘ 正常終了
pptApp.DisplayAlerts = ppAlertsAll
pptApp.Quit
Set pptApp = Nothing

MsgBox “処理が完了しました。総処理ファイル数: ” & processedCount, vbInformation, “Security Enforcer”
Exit Sub

ErrorHandler:
‘ 異常終了時のフォールバック処理(プロセスのゾンビ化を防ぐ)
On Error Resume Next
If Not pptApp Is Nothing Then
pptApp.DisplayAlerts = ppAlertsAll
pptApp.Quit
Set pptApp = Nothing
End If
MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical, “Fatal Exception”
End Sub

Private Sub ProcessDirectory(ByVal folderPath As String, ByRef pptApp As PowerPoint.Application, ByVal encPassword As String, ByRef count As Long)
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)

Dim folder As Object
Set folder = fso.GetFolder(folderPath)

Dim file As Object
Dim targetPres As PowerPoint.Presentation

‘ ディレクトリ内のファイルをループ
For Each file In folder.Files
Dim ext As String
ext = LCase(fso.GetExtensionName(file.Path))

‘ PowerPointの主要拡張子のみをターゲットにする
If ext = “pptx” Or ext = “ppt” Or ext = “pptm” Then

‘ 【重要】ReadWriteモードで排他オープン
‘ すでにパスワードがかかっているファイルはスキップ、あるいはエラーハンドリングする
On Error Resume Next
Set targetPres = pptApp.Presentations.Open(FileName:=file.Path, _
ReadOnly:=msoFalse, _
Untitled:=msoFalse, _
WithWindow:=msoFalse)

If Err.Number <> 0 Then
‘ パスワード保護済みのファイルや、他プロセスによるロック時はスキップ
Err.Clear
GoTo ContinueLoop
End If
On Error GoTo 0

With targetPres
‘ 1. 読み取り専用推奨フラグをTrueに設定
.ReadOnlyRecommended = True

‘ 2. 保存処理(オープンパスワードを同時に付与)
‘ ※ パスワード付き保存は SaveAs メソッドを使用する
.SaveAs FileName:=file.Path, _
FileFormat:=.FileFormat, _
Password:=encPassword

.Close
End With

‘ 参照の明示的破棄
Set targetPres = Nothing
count = count + 1
End If
ContinueLoop:
On Error GoTo 0
Next file

‘ 再帰的にサブディレクトリを処理
Dim subFolder As Object
For Each subFolder in folder.SubFolders
Call ProcessDirectory(subFolder.Path, pptApp, encPassword, count)
Next subFolder

Set fso = Nothing
End Sub

3. チーフアーキテクトが指摘する「実装の急所」

上記のコードは一見シンプルに見えるが、エンタープライズ環境の実戦で耐えうるために、以下のアーキテクチャ上の工夫が組み込まれている。

① `DisplayAlerts` の制御とUIの排除

大量のファイルを扱う際、古いファイルフォーマットの警告や、「上書きしますか?」といったダイアログボックスがポップアップすると、自動化スクリプトはその場で永遠の眠りにつく(ハングする)。
`pptApp.DisplayAlerts = ppAlertsNone` を宣言し、さらに `WithWindow:=msoFalse` でウィンドウレンダリングを完全に抑制することで、CPU負荷を最小限に抑えつつ高速な一括処理を実現している。

② 例外時のゾンビプロセス防止(エラーハンドリング)

VBAで最も恐ろしいのは、ループの途中でランタイムエラーが発生し、メモリ上に `POWERPNT.EXE` のゾンビプロセスが残ることだ。
`ErrorHandler` ラベルにおいて、確実に `.Quit` を実行し、かつ `Set pptApp = Nothing` でCOM参照を完全に切断する設計が不可欠である。

③ パスワード付与とファイルの整合性

PowerPointのオブジェクトモデルにおいて、単に `Password = “xxx”` とプロパティを書き換えるだけでは不十分な場合がある。`SaveAs` メソッドの引数に `Password` を明示的に渡すことで、暗号化ストリームを確実にファイルヘッダに書き込ませる。

4. セキュリティ自動化の未来:VBAの限界と次のステップ

VBAは、Microsoft Officeエコシステム内において依然として強力なランタイムである。しかし、数万ファイル規模のクラウドストレージ連携、あるいはAzure Key Vaultなどの外部秘密情報管理サービス(KMS)と連携した動的なパスワード生成・管理が求められる現代において、VBA単体ではアーキテクチャの限界を迎える。

真にモダンなシステムを目指すのであれば、今回解説したVBAのロジックをベースにしつつ、C# (.NET 8) + OpenXML SDK、あるいは Python (python-pptx) を用いたヘッドレスなバックエンドサーバーへの移行を視野に入れるべきだ。

だが、社内のローカル環境や閉じたネットワークにおいて、今すぐ確実に、そしてセキュアにプレゼンテーション資産を守り抜くための「特効薬」としては、このVBAスクリプトを超える手軽さと確実性はない。

コードを正しく理解し、メモリのライフサイクルを支配する者だけが、システムを意のままに操ることができる。健闘を祈る。

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