【Excel VBA】QPDFを使ってPDFにパスワードを設定する方法

VBA

修正履歴
2020/11/06 サンプルソースの一部表示に問題があったため修正。
・2021/01/31 サンプルソースから「%ComSpec% /c」の記述を削除。

PDFにパスワードを設定する方法

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

QPDFとは?

QPDFとはコマンドライン形式のPDF編集ソフトです。PDFにパスワード等のセキュリティ設定をしたりマージ/分割等を行うことができます。
注目したい特徴は以下の通りです。

  • コマンドライン形式のソフト
  • ライセンス:フリー
  • インストール不要
  • PDFのパスワード等のセキュリティ設定ができる

QPDFを任意の場所に配置さえしておけばVBAからPDFにパスワードを設定できるんです。感動じゃないですか?

QPDF公式サイト
http://qpdf.sourceforge.net/
※QPDFのダウンロード方法について他サイト様でも紹介されているので興味のある方は調べてみてください。

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

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

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

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

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

Option Explicit

Private Const CMD_TEMPLATE As String = "[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を出力するという流れです。

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

8 件のコメント

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

    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でエラーが発生したときの原因がわからないので時間があるときに原因がわかるようなソースに修正検討します。
            ご迷惑おかけします。

  • qPDF を ダウンロードしたので活用しようと思い、このサンプルにたどり着きました。
    上記のエラーは、%COMSPEC%の環境変数が反映されていないことが要因です
    QPDFが正しく実行されていないようです
    したがって、環境変数を設定しようとしましたが、なぜか反映されません
    再起動したり、SETX で設定もしましたが反映されません
    環境変数には追加されています。
    システム環境変数に同じ COMSPECがあるのが原因でしょうか
    反映されない原因は不明です

    いずれにしても、サンプルの %COMSPEC% のところに、実際の cmd変数を記述したら、パスワード付きのpdfが作成されたことを確認しました。

    最近、VBAサンプルを活用しようと思いましたが、同じようなところで止まっていました。
    VBA自体の原因ではないことがわかってVBAをもう少し進化させることができそうです

    • %COMSPEC%から設定値が取れないことがあるのですね。
      原因はわかりませんが対処方法がわかったのでよかったです。
      サンプルも更新しておきます。
      貴重な情報ありがとうございます。

  • hoimins0926 へ返信する コメントをキャンセル

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