社内で新しいWebサービスを導入することになりまして、全社員分のアカウントが作成されるのですが、各アカウントごとに初回ログイン用URLにアクセスしてパスワードを設定する必要があります。
初回ログイン用URLは社員ごとにURLがあり、ハッシュ値のようなランダムの文字列が含まれているので口頭で伝えることは不可能で、文書で伝えても入力するには骨が折れます。
アカウントにメールアドレスが登録されていればメールで初回ログイン用URLを送って、社員はリンクをクリックするだけでアクセスできるのですが、全社員がメールアドレスが持っているわけではなく、その場合の初回ログイン用URLの伝達方法を考えなければなりません。
管理者側で各社員ごとの初回ログイン用URLにアクセスしてパスワードを設定し、そのパスワードを伝達するという方法もありますが、社員が1000人近くいるのでその作業をするのも現実的ではありません。
そこで共有ストレージ上に初回ログイン用URLのリンクが記載されたPDFファイルを社員ごとに作成し、それぞれのPDFファイルを各社員がタイムカード打刻に使用しているパスワードで保護すれば手間なく且つ安全に伝えることができると考えました。
今回はExcel VBAを使ってシートをパスワード保護したPDFとして出力する方法を調べて作成した備忘録です。
Excelでパスワード付きPDFにするにはPDFtkが必要
ってなことが会議で議題にあがって解決策を提示したのですが、あとから調べるとExcelでは標準でPDFにパスワードを付けることができないそう。
いっそExcelの暗号化で済まそうかとも考えましたが、どうやらサードパーティのアプリを使えばなんとかなるそうな。
今回はPDFtkというアプリを使います。参考にしたのは下記リンク。
PDFtkをインストール
インストール版とポータブル版があるのですが、今回は参考サイトにならってポータブル版を使います。
下記リンクにアクセスしてダウンロードします。

ダウンロードリンクがあるのでクリックします。

インストーラーを起動して、あとは肯定的に進めていけばPDFtkのファイル一式が展開されます。

展開したフォルダ内の\App\pdftkbuilder\pdftk.exeをExcel VBAの中で使用します。
フォルダとExcelの準備

フォルダを作成し、その中に下記を準備します。
- 展開したPDFtkのフォルダ
- Excelマクロ実行ブック (ここでは「export-password-pdf.xlsm」としています)
- フォルダ「PDF出力先」
- フォルダ「PW付PDF出力先」

Excelには、まずシート「リスト」に社員の一覧を作成します。1列目から、
- No (社員番号)
- 氏名
- 生年月日 (今回はこれをパスワードの代わりにします)
- 初回ログイン用URL
の順にしています。PDFに載せたい項目を任意で用意します。
もちろんこれはサンプルファイルでして、個人情報テストデータ生成ツールで作成しました。
パスワードについては今回はサンプルで用意するのが面倒だったので、個人情報テストデータ生成ツールで作成できる生年月日をそのまま使うことにしましたが、生年月日は秘密情報ではないので本来はこういった場面でパスワードに使うべきではありません。
実際にはここにタイムカード打刻用パスワードを入力して、社員が各自自身のPDFだけを見られるようにしています。

シート「出力シート」はPDF出力するためのフォーマットを用意します。
何も入力されていませんが、セルA1に「番号: nnnn 氏名 様」、セルA5に初回ログインURLのリンクが入力された状態でPDF出力されます。
出力結果
VBAのコードよりも先に出力結果をば。

「PW付PDF出力先」のフォルダ内に、「nnnn(番号)_氏名.pdf」のPDFが作成されました。
これを共有ストレージに入れて、各社員が自身のPDFを探して開きます。

開くとパスワード入力画面が出ますので、自身のパスワード (今回のサンプルでいえば生年月日) を入力します。

開くと初回ログインURLのリンクが表示されるので、クリックしてアクセスします。
VBA
Sub PW付PDF出力()
Dim userListArray As Variant
Dim userNumber As String
Dim userName As String
Dim loginUrl As String
Dim password As String
Dim EXPORT_PATH As String: EXPORT_PATH = ThisWorkbook.Path & "\PDF出力先"
Dim pdfPath As String
Dim SECURE_EXPORT_PATH As String: SECURE_EXPORT_PATH = ThisWorkbook.Path & "\PW付PDF出力先"
Dim securePdfPath As String
Dim pdftkPath As String: pdftkPath = """C:\Users\hoge\PDFTKBuilderPortable\App\pdftkbuilder\pdftk.exe""" 'pdftk.exeの絶対パスを指定
Dim inputFile As String
Dim outputFile As String
Dim objWSH As Object, objwExec As Object, Result As String
Dim cmd As String
With Worksheets("リスト")
userListArray = .Range(.Cells(2, 1), .Cells(.Cells(Rows.Count, 1).End(xlUp).Row, .Cells(1, Columns.Count).End(xlToLeft).Column)).Value
End With
For i = 1 To UBound(userListArray, 1)
With Worksheets("出力シート")
.Cells(1, 1).ClearContents
.Cells(5, 1).Clear
userNumber = userListArray(i, 1)
userName = userListArray(i, 2)
password = userListArray(i, 3)
loginUrl = userListArray(i, 4)
.Cells(1, 1).Value = "番号: " & userNumber & " " & userName & " 様"
.Cells(5, 1).Hyperlinks.Add anchor:=.Cells(5, 1), Address:=loginUrl, TextToDisplay:=loginUrl
pdfPath = EXPORT_PATH & "\" & userNumber & "_" & userName
.ExportAsFixedFormat Type:=xlTypePDF, _
Filename:=pdfPath, _
Quality:=xlQualityStandard, _
IncludeDocProperties:=True, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=False
'PDFtkでパスワード保護
Set objWSH = CreateObject("WScript.Shell")
inputFile = Chr(34) + pdfPath + ".pdf" + Chr(34)
outputFile = Chr(34) + SECURE_EXPORT_PATH + "\" & userNumber & "_" & userName & ".pdf" + Chr(34)
cmd = "%ComSpec% /c " + Chr(34) + pdftkPath + " " + inputFile + " output " + outputFile + " user_pw " + password + Chr(34)
Set objwExec = objWSH.Exec(cmd)
Do While objwExec.Status = 0
DoEvents
Loop
End With
Next i
End Sub
流れとしては、2次元配列に格納した社員リストを走査して、出力用シートに入力したものを一旦普通のPDFファイルに出力、そのPDFファイルに対してシェルで呼び出したPDFtkを使ってパスワードをつけて再出力します。つまりパスワードが付いているPDFとそうでないPDFの2種類ができあがります。
13行目はpdftk.exeの場所を絶対パスで指定しています。これはシェルで呼び出す時に使用します。
今回はマクロ実行ブックと同じフォルダ内にポータブル版を入れたので、ThisWorkbook.Pathを使って記述を簡略化できそうではありましたが、なぜかうまくいかなかったのでこの書き方です。おそらくダブルクォートの付き方が変だっただけだと思うのでちゃんとやればできそうですが、面倒くさくなって追求しませんでした。
コメント