【入門編】【上級者】SharePoint/Teams上の共同編集環境で発生する保存競合(コンフリクト)をVBA側で検知し、データ消失を防ぐためにローカルへタイムスタンプ付き退避コピーを自動生成するリスク回避マクロ – PowerPoint VBA解析バイブル

スポンサーリンク
スポンサーリンク

クラウドの罠を回避せよ:SharePoint/Teams環境でのデータ消失を防ぐ「極限の退避マクロ」

こんにちは。自動化の世界へようこそ。

「せっかく作り上げたスライドが、保存ボタンを押した瞬間にエラーが出て消えてしまった……」
「SharePointで共同編集していたら、自分の変更が上書きされてしまった……」

もし君がそんな経験をしたことがあるなら、それは君のせいではありません。それは、「ローカル(自分のPC)の常識」と「クラウド(SharePoint/Teams)の作法」が衝突しているから起こる、エンジニアリング上の構造的な問題なのです。

今日は、マクロの記録(Record Macro)という初歩的な段階を卒業し、一歩上の「リスク管理ができるエンジニア」になるための、非常に実践的なテクニックを伝授します。

題して、「共同編集環境における保存競合(コンフリクト)検知&ローカル強制退避機構」の構築です。

1. なぜ「普通の保存」ではいけないのか?

まず、問題の本質を理解しましょう。ここを飛ばすと、どんなに綺麗なコードを書いても「動かないコード」になってしまいます。

クラウドとVBAの「時間のズレ」

PowerPointの共同編集(Co-authoring)は、クラウド上で複数のユーザーが「バラバラのタイミング」でデータを同期しています。しかし、VBAのプログラムは「同期的な命令」です。

1. VBAが「ファイルを保存せよ!」と命令を出す。
2. その瞬間、ちょうど他の誰かがクラウド上のファイルを更新中だった。
3. SharePointが「今、ファイルはロックされている(または競合している)から保存できないよ!」と拒絶する。
4. VBAはエラーを吐いて停止する。
5. 結果:メモリ上にしかない「君が今書いた最新のデータ」が、保存されずに消えてしまう可能性がある。

この「拒絶」を検知し、エラーで止まるのではなく、「じゃあ、とりあえず手元のデスクトップに避難させよう!」と動くのが、プロフェッショナルな設計思想です。

2. 設計図:守りのアルゴリズム

今回のマクロが取るべき戦略は、以下のフローです。

1. 【試行】 まずは、いつものようにクラウド上のファイルへ `Save` を試みる。
2. 【検知】 もしエラーが発生したら、それを「衝突(コンフリクト)」とみなして捕まえる(`On Error`)。
3. 【退避】 エラーが起きたら、即座に「ローカルのデスクトップ」へ、現在時刻を付与したファイル名で `SaveAs`(名前を付けて保存)を実行する。
4. 【通知】 ユーザーに「クラウド保存は失敗したけど、ローカルにバックアップを作ったよ!」と優しく教える。

3. 実装:プロテクト・マクロのコード

さあ、準備はいいですか? これが、現場でそのまま使えるレベルのコードです。

Option Explicit

''' <summary>
''' クラウド上の保存失敗を検知し、ローカルへバックアップを作成するプロテクト関数
''' </summary>
Sub SafeCloudSave()
    Dim targetPres As Presentation
    Dim currentPath As String
    Dim desktopPath As String
    Dim timestamp As String
    Dim backupFileName As String
    Dim saveSuccess As Boolean
    
    Set targetPres = ActivePresentation
    saveSuccess = False
    
    ' 1. 現在のファイルパスを取得
    currentPath = targetPres.FullName
    
    ' ファイルが一度も保存されていない(新規作成直後)場合は、通常の保存を試みる
    If currentPath = "" Then
        MsgBox "このファイルはまだ保存されていません。まずは一度名前を付けて保存してください。", vbExclamation
        Exit Sub
    End If

    ' --- 運命の分岐点:エラーハンドリング開始 ---
    On Error Resume Next ' エラーが起きても止まらず、次の行へ進む(ここが重要!)
    
    ' 2. クラウドへの保存を試みる
    targetPres.Save
    
    ' エラーが発生したかチェック
    If Err.Number <> 0 Then
        ' エラーが発生した場合、ここを通る
        Debug.Print "Save Error Detected: " & Err.Description
        
        ' 3. ローカルへの退避準備
        ' デスクトップのパスを取得(ユーザー環境に依存しない書き方)
        desktopPath = CreateObject("WScript.Shell").SpecialFolders("Desktop")
        
        ' タイムスタンプの生成 (例: 20231027_153045)
        timestamp = Format(Now, "yyyymmdd_hhmmss")
        
        ' バックアップ用のファイル名を作成 (元のファイル名_タイムスタンプ.pptx)
        ' 拡張子を除いたファイル名を取得するために、ファイルパスを分解
        Dim baseName As String
        baseName = Left(targetPres.Name, InStrRev(targetPres.Name, ".") - 1)
        backupFileName = desktopPath & "\" & baseName & "_BACKUP_" & timestamp & ".pptx"
        
        ' 4. ローカルへ強制退避 (SaveAs)
        targetPres.SaveAs Filename:=backupFileName
        
        ' SaveAsが成功したか再チェック
        If Err.Number = 0 Then
            saveSuccess = True
        Else
            ' 退避すら失敗した場合(ディスク容量不足など)
            MsgBox "致命的なエラー: クラウドへの保存も、ローカルへの退避も失敗しました!" & vbCrLf & _
                   "作業内容が失われる可能性があるため、すぐに手動でコピーを取ってください。", vbCritical
            Err.Clear
        End If
    Else
        ' エラーなし(正常に保存できた場合)
        saveSuccess = True
    End If
    On Error GoTo 0 ' エラーハンドリングを元に戻す
    ' --- エラーハンドリング終了 ---

    ' 5. ユーザーへのフィードバック
    If saveSuccess Then
        If Err.Number <> 0 Then ' 保存はできたが、エラーを検知した経緯がある場合
             MsgBox "【注意】クラウドへの保存に失敗したため、デスクトップに退避コピーを作成しました。" & vbCrLf & _
                    "ファイル名: " & backupFileName, vbInformation, "クラウド競合検知"
        Else
             ' 通常の成功(メッセージは出さなくても良いが、デバッグ用に残すことも可)
             ' MsgBox "保存が完了しました。", vbInformation
        End If
    End If
End Sub

4. 技術解説:コードの「魂」を読み解く

このコードがなぜ「強い」のか。その核心を解説します。

① `On Error Resume Next` の正しい使い方

初心者は「エラーが出たら止まる」のが当たり前だと思っています。しかし、業務自動化においては「エラーを予測して、エラーが起きた後のプランBを用意する」ことが求められます。
ここでは、`Save` が失敗することを「想定内」として扱い、エラーが発生してもプログラムを強制終了させずに、次の「退避処理」へ流し込むために使用しています。

② `WScript.Shell` による環境依存の排除

`C:\Users\Taro\Desktop` のようにパスを直接書くのは、プロの仕事ではありません。使う人によって名前が違うからです。
`CreateObject(“WScript.Shell”).SpecialFolders(“Desktop”)` を使うことで、「誰のPCで動かしても、その人のデスクトップ」を正確に指し示すことができます。これが「汎用性」です。

③ `Save` と `SaveAs` の使い分け

ここが最も重要なアーキテクチャのポイントです。

  • `Save`: 「今開いている場所(クラウド)」に書き込もうとする。失敗しやすい。
  • `SaveAs`: 「新しい場所(ローカル)」に新しいファイルとして書き出す。クラウドのロックの影響を受けにくい。

競合が起きたときに `SaveAs` を使うことで、「現在のメモリ上の最新データ」を、安全な場所へ確実に着地させることができるのです。

5. さらなる高みへ:エンジニアとしてのマインドセット

このマクロをマスターした君へ。次のステップとして、以下のことを考えてみてください。

  • 「もしデスクトップが満杯だったら?」: エラー処理の中に、さらにエラー処理を重ねる(ネストする)設計。
  • 「自動で実行するには?」: `Presentation.OnSave` イベント(※PowerPointでは少し特殊な実装が必要ですが)を利用して、ユーザーが保存ボタンを押した瞬間にこのロジックが走るようにする。

最後に

プログラミングは、単に命令を並べる作業ではありません。「ユーザーが直面する最悪の事態を、いかにエレガントに回避するか」という、優しさの設計なのです。

このマクロを導入することで、君のチームのメンバーは「保存エラー」の恐怖から解放されるでしょう。それこそが、優れたエンジニアが提供できる最高の価値です。

さあ、自信を持って、このコードを君のプロジェクトに組み込んでみてください。応援していますよ。

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