Excel VBAを使って、複数のシートをPDFとして出力し、最後にWindowsの copy /b コマンドで1つのPDFファイルにまとめる方法を紹介します。
Acrobat APIやPDFtkなどの外部ソフトを使えない環境でも試せる簡易的な方法ですが、PDFの構造によっては正常に連結できない場合があります。
そのため、正式なPDF結合処理ではなく、社内確認用・一時利用向けのサンプルとして参考にしてください。
copy /b によるPDF連結は、正式なPDF結合方法ではありません。PDFの構造によっては、ページが正しく表示されない、ファイルが壊れる、閲覧ソフトによって結果が変わる可能性があります。
重要な書類では、Acrobat API、PDFtk、Power Automate、専用ライブラリなどの利用を検討してください。
このマクロで行う処理
このマクロでは、指定した条件に合うシートを探し、個別にPDFとして出力したあと、最後に1つのPDFファイルへ簡易連結します。
- 画面更新を停止して、処理速度を上げる。
- 「印刷」シートの前回結果をクリアする。
- 「データ」シートから印刷対象の店番リストを取得する。
- すべてのワークシートを確認する。
- 除外対象のシートはスキップする。
- B2またはC4の店番を確認し、対象シートか判定する。
- 印刷範囲と書式を設定する。
- 対象シートを一時PDFとして出力する。
- 出力した一時PDFを
copy /bで簡易連結する。 - 処理が終わったら、一時PDFを削除する。
事前に確認すること
このサンプルでは、次のシート構成を想定しています。
- データ:印刷対象となる店番リストをA列に持つシート。
- 印刷:印刷対象となったシート名を書き出すシート。
- その他のシート:B2またはC4に店番が入っている印刷対象候補のシート。
また、サンプルではシート保護解除用のパスワードを 1234 としています。実際に使用する場合は、ご自身の環境に合わせて変更してください。
サンプルでは説明を分かりやすくするため、シート保護のパスワードをコード内に直接記述しています。
実務で使う場合は、パスワード管理に注意してください。
① メイン処理:対象シートをPDF出力して簡易連結する
まずはメイン処理です。
すべてのシートを確認し、対象となる店番が含まれているシートだけをPDFとして出力します。最後に、作成した一時PDFを1つにまとめます。
VBAコード
Sub WriteSheetsToPrintAndMergePDFs()
Dim ws As Worksheet
Dim dataSheet As Worksheet
Dim printSheet As Worksheet
Dim fukuokaShops As Object
Dim tempPDFs As Object
Dim shopCode As Variant
Dim shopList As Variant
Dim excludeSheets As Variant
Dim i As Long
Dim printRow As Long
Dim isB2 As Boolean
Dim sheetName As String
Dim password As String
Dim tempPDFPath As String
Dim finalPDFPath As String
Dim printRange As Range
On Error GoTo ErrHandler
'=== 画面更新などを停止して処理速度を向上 ===
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.DisplayAlerts = False
Application.StatusBar = "処理を開始しています..."
'=== シートをセット ===
Set dataSheet = ThisWorkbook.Sheets("データ")
Set printSheet = ThisWorkbook.Sheets("印刷")
'=== 除外するシートリスト ===
excludeSheets = Array("データ", "データ2", "データ3", "印刷")
'=== 「印刷」シートの前回結果をクリア ===
printSheet.Range("A2:A1000").ClearContents
'=== 店番リストを辞書に格納 ===
Set fukuokaShops = CreateObject("Scripting.Dictionary")
shopList = dataSheet.Range("A2:A" & dataSheet.Cells(dataSheet.Rows.Count, 1).End(xlUp).Row).Value
For i = LBound(shopList, 1) To UBound(shopList, 1)
If Len(Trim(CStr(shopList(i, 1)))) > 0 Then
If Not fukuokaShops.Exists(CStr(shopList(i, 1))) Then
fukuokaShops.Add CStr(shopList(i, 1)), True
End If
End If
Next i
'=== 一時PDFファイルリストを作成 ===
Set tempPDFs = CreateObject("Scripting.Dictionary")
printRow = 2
password = "1234"
'=== すべてのシートを確認 ===
For Each ws In ThisWorkbook.Worksheets
isB2 = False
sheetName = ws.Name
Set printRange = Nothing
Application.StatusBar = "処理中: " & sheetName & " を確認中..."
' 除外リストにあるシートはスキップ
If IsSheetExcluded(sheetName, excludeSheets) Then
GoTo NextSheet
End If
' シート保護解除
If ws.ProtectContents Then
On Error Resume Next
ws.Unprotect Password:=password
On Error GoTo ErrHandler
End If
' B2の店番を確認
If Len(Trim(CStr(ws.Range("B2").Value))) > 0 Then
shopCode = CStr(ws.Range("B2").Value)
If fukuokaShops.Exists(shopCode) Then
isB2 = True
Set printRange = ws.Range("A1:T60")
End If
' C4の店番を確認
ElseIf Len(Trim(CStr(ws.Range("C4").Value))) > 0 Then
shopCode = CStr(ws.Range("C4").Value)
If fukuokaShops.Exists(shopCode) Then
isB2 = False
Set printRange = ws.Range("A1:M46")
End If
End If
' 印刷対象ではない場合はスキップ
If printRange Is Nothing Then
GoTo NextSheet
End If
' 「印刷」シートにシート名を記録
printSheet.Cells(printRow, 1).Value = sheetName
printRow = printRow + 1
' 書式設定を適用
Call ApplyFormatting(ws, printRange, isB2)
' PDFを一時出力
tempPDFPath = Environ("TEMP") & "\" & CleanFileName(sheetName) & ".pdf"
ws.ExportAsFixedFormat Type:=xlTypePDF, _
Filename:=tempPDFPath, _
Quality:=xlQualityStandard, _
IncludeDocProperties:=True, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=False
' 一時PDFをリストに追加
If Not tempPDFs.Exists(tempPDFPath) Then
tempPDFs.Add tempPDFPath, tempPDFPath
End If
NextSheet:
Next ws
'=== 最終PDFの保存先 ===
finalPDFPath = Environ("USERPROFILE") & "\Documents\福岡店番データ.pdf"
'=== PDFの簡易連結 ===
If tempPDFs.Count > 0 Then
Application.StatusBar = "PDFを簡易連結しています..."
Call MergePDFs_Copy(tempPDFs, finalPDFPath)
Else
MsgBox "PDF出力対象のシートがありませんでした。", vbExclamation
End If
ExitHandler:
'=== 設定を必ず元に戻す ===
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.DisplayAlerts = True
Application.StatusBar = False
Exit Sub
ErrHandler:
MsgBox "エラーが発生しました:" & Err.Description, vbExclamation
Resume ExitHandler
End Sub
② 除外リストチェック関数
この関数は、現在チェックしているシートが除外対象かどうかを判定します。
たとえば、「データ」「データ2」「データ3」「印刷」など、PDF出力したくないシートをスキップするために使います。
VBAコード
Function IsSheetExcluded(sheetName As String, excludeSheets As Variant) As Boolean
Dim i As Long
IsSheetExcluded = False
For i = LBound(excludeSheets) To UBound(excludeSheets)
If sheetName = excludeSheets(i) Then
IsSheetExcluded = True
Exit Function
End If
Next i
End Function
③ copy /bを使ったPDFの簡易連結処理
この処理では、個別に出力したPDFファイルを、Windowsの copy /b コマンドで1つのファイルに連結します。
ただし、PDFの内部構造を正しく再構成する処理ではありません。PDFによっては正常に開けない場合があります。
また、通常の Shell だけで実行すると、コマンドの完了を待たずに次の処理へ進むことがあります。そこで今回は WScript.Shell の Run を使い、コマンドが完了してから一時PDFを削除する形にしています。
VBAコード
Sub MergePDFs_Copy(tempPDFs As Object, outputPDF As String)
Dim pdfList As String
Dim tempPDF As Variant
Dim command As String
Dim wsh As Object
Dim result As Long
pdfList = ""
' PDFファイルのリストを作成
For Each tempPDF In tempPDFs
pdfList = pdfList & " """ & tempPDF & """"
Next tempPDF
' Windowsコマンドを作成
command = "cmd /c copy /b " & pdfList & " """ & outputPDF & """"
Set wsh = CreateObject("WScript.Shell")
' 第3引数 True で、コマンドの完了を待つ
result = wsh.Run(command, 0, True)
If result = 0 Then
' コマンド成功後に一時PDFを削除
For Each tempPDF In tempPDFs
If Dir(CStr(tempPDF)) <> "" Then
Kill CStr(tempPDF)
End If
Next tempPDF
MsgBox "PDFの簡易連結が完了しました。" & vbCrLf & "保存場所:" & outputPDF, vbInformation
Else
MsgBox "PDFの簡易連結処理でエラーが発生しました。" & vbCrLf & _
"一時PDFは削除していません。", vbExclamation
End If
End Sub
この方法は、PDFをバイナリとして連結する簡易的な方法です。
「複数PDFのページを正しく結合する」処理とは異なるため、作成後は必ずPDFを開いて確認してください。
④ 書式設定
この処理では、PDF出力前にフォントや印刷範囲、余白などを設定します。
B2に店番があるシートと、C4に店番があるシートで印刷範囲が違う想定になっています。
VBAコード
Sub ApplyFormatting(ws As Worksheet, printRange As Range, isB2 As Boolean)
' フォント設定
With printRange.Font
.Name = "Arial"
.Size = 12
.Bold = True
End With
' B2のシートのみ特別設定
If isB2 Then
With ws.Range("A6:T12").Font
.Size = 14
.Bold = True
End With
ws.Columns("S:S").AutoFit
End If
' 印刷設定
With ws.PageSetup
.PrintArea = printRange.Address
.Orientation = xlPortrait
.PaperSize = xlPaperA4
If isB2 Then
.LeftMargin = Application.InchesToPoints(0.3)
.RightMargin = Application.InchesToPoints(0.3)
.TopMargin = Application.InchesToPoints(0.6)
.BottomMargin = Application.InchesToPoints(0.6)
Else
.LeftMargin = Application.InchesToPoints(0.6)
.RightMargin = Application.InchesToPoints(0.6)
.TopMargin = Application.InchesToPoints(0.9)
.BottomMargin = Application.InchesToPoints(0.9)
End If
.CenterHorizontally = True
.CenterVertically = True
End With
End Sub
⑤ ファイル名に使えない文字を除去する関数
シート名によっては、PDFファイル名に使えない文字が含まれている場合があります。
そのままPDF出力するとエラーになる可能性があるため、ファイル名として使えない文字を除去する関数を用意しておくと安全です。
VBAコード
Function CleanFileName(ByVal fileName As String) As String
Dim invalidChars As Variant
Dim i As Long
invalidChars = Array("\", "/", ":", "*", "?", """", "<", ">", "|")
For i = LBound(invalidChars) To UBound(invalidChars)
fileName = Replace(fileName, invalidChars(i), "_")
Next i
CleanFileName = fileName
End Function
カスタマイズのポイント
保存先を変更したい場合
最終PDFの保存先は、次の部分で指定しています。
finalPDFPath = Environ("USERPROFILE") & "\Documents\福岡店番データ.pdf"
たとえばデスクトップに保存したい場合は、次のように変更できます。
finalPDFPath = Environ("USERPROFILE") & "\Desktop\福岡店番データ.pdf"
除外するシートを変更したい場合
除外するシートは、次の配列で指定しています。
excludeSheets = Array("データ", "データ2", "データ3", "印刷")
除外したいシートを増やす場合は、この中にシート名を追加してください。
印刷範囲を変更したい場合
B2に店番があるシートの印刷範囲は、次の部分です。
Set printRange = ws.Range("A1:T60")
C4に店番があるシートの印刷範囲は、次の部分です。
Set printRange = ws.Range("A1:M46")
実際の帳票レイアウトに合わせて、セル範囲を変更してください。
この方法を使うときの注意点
copy /bは正式なPDF結合処理ではありません。- PDFによっては、正常に開けない場合があります。
- 閲覧ソフトによって表示結果が変わる可能性があります。
- 重要書類や提出用PDFには、専用ツールの利用をおすすめします。
- 作成後は、必ずPDFを開いて内容を確認してください。
まとめ
| 処理 | 内容 |
|---|---|
| ① メイン処理 | 印刷対象のシートを探し、個別PDFとして出力する。 |
| ② 除外リストチェック | 印刷しないシートを判定してスキップする。 |
| ③ PDF簡易連結 | Windowsの copy /b で複数PDFを1つのファイルに連結する。 |
| ④ 書式設定 | 印刷前にフォントサイズ、印刷範囲、余白を整える。 |
| ⑤ ファイル名整形 | PDF出力時に使えない文字を除去する。 |
Excel VBAの ExportAsFixedFormat を使うと、シートをPDFとして出力できます。
さらに、Windowsの copy /b コマンドを組み合わせることで、外部ソフトを使わずに複数PDFを1つのファイルへ簡易連結できます。
ただし、この方法はPDFの内部構造を正しく結合するものではありません。重要な書類で使う場合は、PDF結合専用の方法を検討してください。


コメント