【Excel VBA】PDFにパスワードを設定する

VBA

※2020/11/06 サンプルソースの一部表示に問題があったため修正しました。

「VBAで出力したPDFにパスワードをかけたい」
たまにそのような話を聞くのですが、調べてみるとVBAだけでは実現できないようです。
そもそもExcelからPDF形式に保存はできますが標準機能ではパスワード設定ができません。
VBAでパスワードを設定するにはAcrobatに付属しているアドインを利用するか各社が出しているPDF編集ソフトを入手する必要があります。
いろいろ調べたところ、コマンドラインで利用できるQPDFというソフトがVBAと相性が良さそうなので使ってみることにしました。

パスワードを設定するサンプルソース

とりあえずVBAでサンプルを作ってみました。
マクロ入りのシートは以下のような感じで作ってます。

PDFファイルは、Excelファイルと同じディレクトリに拡張子をPDFに変えて出力する仕様にしています。

サンプルで確認した際にQPDFは以下のようにDドライブへ配置しています。

ソースコードは以下の通り。

Option Explicit

Private Const CMD_TEMPLATE As String = "%ComSpec% /c [QpdfPath] --encrypt [UserPassword] [OwnerPassword] 256 -- [PdfInputPath] [PdfOutputPath]"

Sub test()
    Dim wb As Workbook
    Dim pos As Long
    Dim cmd As String
    Dim wsh As Object
    Dim result As Object
    Dim QpdfPath As String
    Dim BookPath As String
    Dim SheetName As String
    Dim UserPassword As String
    Dim PdfInputPath As String
    Dim PdfOutputPath As String
    
    ' 確認メッセージ
    If MsgBox("PDFを出力します。よろしいですか?", vbYesNo + vbQuestion) = vbNo Then
        Exit Sub
    End If

    ' 画面更新停止
    Application.ScreenUpdating = False

    ' 設定値取得
    QpdfPath = ActiveSheet.Cells(2, 3).Value
    BookPath = ActiveSheet.Cells(3, 3).Value
    SheetName = ActiveSheet.Cells(4, 3).Value
    UserPassword = ActiveSheet.Cells(5, 3).Value

    ' PDFファイルパス生成
    pos = InStrRev(BookPath, ".")
    If pos > 0 Then
        PdfOutputPath = Replace(BookPath, LCase(Mid(BookPath, pos + 1)), "pdf")
    End If
    PdfInputPath = PdfOutputPath & "_tmp.pdf"
    
    ' EXCELをPDF形式で保存
    Set wb = Workbooks.Open(BookPath)
    wb.Worksheets(SheetName).ExportAsFixedFormat Type:=xlTypePDF, Filename:=PdfInputPath
    Call wb.Close(SaveChanges:=False)
    
    ' コマンド作成
    cmd = CMD_TEMPLATE
    cmd = Replace(cmd, "[QpdfPath]", QpdfPath)
    cmd = Replace(cmd, "[UserPassword]", UserPassword)
    cmd = Replace(cmd, "[OwnerPassword]", Chr(34) & Chr(34))
    cmd = Replace(cmd, "[PdfInputPath]", Chr(34) & PdfInputPath & Chr(34))
    cmd = Replace(cmd, "[PdfOutputPath]", Chr(34) & PdfOutputPath & Chr(34))
        
    ' コマンド実行(QPDF)
    Set wsh = CreateObject("WScript.Shell")
    Set result = wsh.exec(cmd)
    Do While result.Status = 0
        DoEvents
    Loop
    Set result = Nothing
    Set wsh = Nothing
    
    ' 入力用PDFファイル削除
    Kill PdfInputPath

    ' 画面更新開始
    Application.ScreenUpdating = True
    
    ' 完了メッセージ
    MsgBox ("完了しました。")
    
End Sub

CMD_TEMPLATE にコマンドの構文を定義しています。

256はパスワードの暗号化の鍵長です。40、126、256から選択できます。

処理はExcel標準機能でPDFを作った後、そのPDFを入力ファイルとしてQPDFでパスワード入りのPDFを出力するという流れです。

エラー処理とか考慮してないのでもっと洗練できそうですが、とりあえずパスワードを設定するという目的は達成できたので、備忘録として公開しておきます。

6 件のコメント

  • プログラムには全くの素人ですが、この機能を利用したくご指導願い致します。

    37行目、PdfInputPath = PdfOutputPath & “_tmp.pdf”でコンパイルエラーが発生してしまいます。

    どのように対処したらよろしいのでしょうか。

    • コメントありがとうございます。
      確認したところサイトの不具合で[&]が[& amp;]で表示されていました。
      これが原因でコンパイルエラーになっていました。大変失礼しました。
      修正しましたのでご確認ください。

      • 改善しました。ありがとうございました。
        新たに確認したいことがあります。
        スクリプトの最後の「完了しました」と表示がでますがファイルが見当たりません。
        どこに、どのような名前でpdfファイルが保存されるのでしょうか。
        ご教示の程、よろしくお願い致します。

        • サンプルソースと同じであれば元のExcelファイルと同じフォルダに同じ名前で作成されます。(A.xls ⇒ A.pdf)
          何もファイルがない場合はQPDFの実行が失敗している可能性が高いです。
          (サンプルソースはQPDFの実行結果が正常/失敗に関係なく、処理を続けるロジックになっているので)

          失敗している原因まではわかりかねますが、上手くいかない場合はまずqpdf.exeを直接ダブルクリックしてエラーにならないか確認してください。
          問題なければコマンドプロンプト(黒い画面)が一瞬立ち上がってすぐに終了するはずです。
          異常があれば何かメッセージが出ると思います。
          また、私がお客様のPCにQPDFを入れた際はセキュリティソフトが実行を妨げていたので、セキュリティソフトからQPDFを除外するように設定したケースもありました。

          デバッグすることが可能であれば、54行目の「cmd」に実行コマンドが設定されるので、そのコマンドをコピーして
          コマンドプロンプトから自分で実行してみるという手もあります。
          エラーであればコマンドプロンプト上にメッセージが出ると思います。

          • お世話になっております。返信ありがとうございます。
            早速、パスやQPDFの動作を確認してみましたが問題はなさそうです。
            解ったことが、42行目までのプログラム実行においてsample.pdfは生成されませんでした。また、仮にsample.pdfをsample.xlsxと同じフォルダに置いてプログラムを実行してもsample.pdfにパスワードは付与しませんでした。
            何かお気づきの点などございましたらご教示願います。

          • 解説しますと41行目の実行でパスワードなしのPDF(sample_tmp.pdf)が一時的に作成されます。
            54行目の実行でパスワードなしのPDF(sample_tmp.pdf)⇒パスワード付きのPDF(sample.pdf)を生成して62行目でパスワードなしのPDF(sample_tmp.pdf)を削除します。

            サンプルソースではQPDFでエラーが発生したときの原因がわからないので時間があるときに原因がわかるようなソースに修正検討します。
            ご迷惑おかけします。

  • コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です