Excel VBAで見積書や請求書をPDFに出力できるようになると、次に困るのが「ファイル名」と「保存先」です。
例えば、次のようなトラブルです。
- 同じ日に同じ顧客へ2回見積書を出したら、前回のPDFが黙って上書きされていた
- 顧客名に「/」が入っていて、マクロがエラーで止まった
- フォルダにPDFが溜まって、どれが最新か分からない
どれも、PDF出力の1行だけを書いて済ませていると、いずれ起きます。
この記事では、Excel VBAで見積書・請求書の作成を自動化する方法で作ったマクロのPDF出力部分を、実務で使える形に育てる方法を解説します。
結論を先に言うと、対策は「ファイル名は部品(関数)で作る」「保存前に同名ファイルを確認する」「年月ごとのフォルダに分けて保存する」の3点です。
PDF出力の「1行版」で起きる3つの困りごと
いちばんシンプルなPDF出力は、次の1行です。上で紹介した記事のマクロも、この形でPDFを出力していました。
wsTemplate.ExportAsFixedFormat Type:=xlTypePDF, Filename:=savePath & customerName & "_見積書_" & Format(Date, "yyyymmdd") & ".pdf"
動くことは動くのですが、実務で使い始めると次の3つにぶつかります。
| 困りごと | 何が起きるか |
|---|---|
| 同名ファイルの上書き | 同じ顧客に同じ日に2回出すと、確認なしで前回のPDFが上書きされる。修正前の見積書を後から見返せない |
| ファイル名に使えない文字 | 顧客名に半角の「/」「:」「?」などが含まれていると、保存の瞬間にエラーで止まる(「A/B商事」なら「ドキュメントを保存できませんでした」と表示される)。全角の「/」「:」なら問題なく保存できるため、入力のしかたによって止まったり止まらなかったりする |
| PDFが1つのフォルダに溜まる | 保存先が1か所なので、使い続けるうちに何十件・何百件と並び、目当ての見積書を探しにくくなる |
顧客名に半角の記号が入っていたときのエラー画面

エラーの文面からは原因が顧客名の記号だと分からないため、気づくまでに時間がかかりがちです。
完成イメージ
今回のマクロを実行すると、ブックと同じ場所に次のようにPDFが並びます。
見積書\
└── 2026年10月\
├── 20261004_A商事_見積書.pdf
├── 20261004_A商事_見積書_2.pdf ← 同じ日に2回目を出した分(前回は消えない)
└── 20261004_B工業_見積書.pdf
処理の流れは次の6ステップです。
- 保存先チェック(OneDrive/SharePoint上なら中断)
- 顧客名から、ファイル名に使えない文字を取り除く
- 「見積書\yyyy年mm月\」フォルダを用意する
- 「yyyymmdd_顧客名_見積書」のファイル名を作り、同名ファイルがあれば「_2」「_3」を付ける
- 印刷設定をA4縦・横1ページに揃える
- PDF出力(作成者名などは入れない)

コードに入る前に、「PDF出力の命令で指定できる設定」と「ファイル名のルール」を順に確認しておきます。
PDF出力の命令で指定できる設定
VBAでシートをPDFにするときは、ExportAsFixedFormat(エクスポート・アズ・フィックスト・フォーマット)という命令を使います。
冒頭の1行版では、「どの形式で出すか(Type)」と「どこに保存するか(Filename)」の2つしか指定していませんでした。
この命令には、ほかにも画質やPDFを自動で開くかどうかなど、細かい設定を追加で指定できます(こうした命令に渡す設定を「引数(ひきすう)」と呼びます)。
今回のコードでは、次の6つを指定します。
| 設定名 | 何を決めるか | 今回の指定 |
|---|---|---|
Type | 出力する形式 | xlTypePDF(PDF) |
Filename | 保存先のフォルダとファイル名 | 「ブックと同じフォルダ\見積書\2026年10月\20261004_A商事_見積書.pdf」のような保存先(コードの中で日付・顧客名から自動で作ります) |
Quality | 画質(標準/最小) | xlQualityStandard(標準) |
IncludeDocProperties | Excelファイルの作成者名などの情報をPDFに引き継ぐか | False(引き継がない) |
IgnorePrintAreas | シートに設定した印刷範囲を無視するか | False(印刷範囲どおりに出力する) |
OpenAfterPublish | 出力後にPDFを自動で開くか | False(開かない。何件も続けて出力するときに邪魔になるため) |
このうち IncludeDocProperties は、Excelファイルに記録されている作成者名(Officeのユーザー名=多くの場合は個人名)などを、PDFに入れるかどうかの設定です。True にすると、取引先に送るPDFのプロパティに、担当者の個人名が入ったままになります。
Excelの画面で「名前を付けて保存」からPDFにした場合も、初期設定のままだと作成者名がPDFに入ります。
手元のExcelで試したところ、この設定を省略した1行版では、作成者名はPDFに入りませんでした。
ただ、省略したときの扱いは公式のリファレンスに書かれていないため、今回のコードでは False を明示しています。
ファイル名のルールをどう決めるか
コードを書く前に、ファイル名のルールを決めておきます。ここは正解が1つではないので、何を優先するかで選びます。
日付を先頭にするか、顧客名を先頭にするか
| ルール | 並び方 | 向いている運用 |
|---|---|---|
20261004_A商事_見積書.pdf(日付先頭) | エクスプローラで日付順に並ぶ | 「今月出した見積書を順に確認する」運用 |
A商事_見積書_20261004.pdf(顧客名先頭) | 顧客ごとにまとまって並ぶ | 「この顧客に過去いつ出したか」を探す運用 |
今回は日付先頭にしました。
年月フォルダに分けたうえで日付順に並べば、月次の確認がそのまま上から順にできるからです。
顧客ごとに探すことが多ければ、顧客名先頭に変えてください(サンプルコードの手順4にある baseName = ... の1行を書き換えるだけです)。
ファイル名に使えない文字
Windowsでは、ファイル名に次の半角9文字が使えません。
\ / : * ? " < > |
もう1つ見落としやすいのが、セル内の改行です。
セルの中で Alt+Enter を押して入れた改行や、タブなどの特殊な文字(制御文字)も、ファイル名には使えません。
「株式会社○○」と「東京支店」を2行に分けて入力しているような顧客名は、そのままではファイル名にできないということです。
顧客名は相手の社名をそのまま使うので、自分では選べません。
そこで、顧客名をファイル名に使う前に、これらの文字を「_」に置き換える処理を必ず通します。
なお、全角の「/」「:」「?」などは半角とは別の文字として扱われるため、ファイル名にそのまま使えます。置き換えが必要なのは、半角の9文字と改行・タブなどの制御文字です。
同名があったら「上書き確認」か「連番」か
同名ファイルがあるときの対応は2通りあります。
- 上書きしますか?と確認する:シンプルだが、確認ダイアログを押し間違えると前回分が消える
- 連番を付けて別名で保存する:前回分が消えない。どれが最新かは番号で分かる
今回は連番を選びました。見積書は「修正前の版を後から見たい」ことがあるため、消える可能性のある方式は避けたかったからです。
サンプルコード
コードの構成
コードは役割ごとに、次の3つのまとまりに分けています。
自分で実行するのは ExportEstimatePdf だけです。
残りの2つは、ExportEstimatePdf が動いている途中で自動的に使われる「部品」なので、個別に実行する必要はありません。
ExportEstimatePdf:PDF出力の本体。実行するのはこのマクロSanitizeFileName:ファイル名に使えない文字を「_」に置き換える部品GetUniquePath:同名ファイルがあれば「_2」「_3」を付ける部品
前提とするExcelファイル
このコードは、次の状態のExcelファイルで動かすことを前提にしています。
- 「見積書テンプレート」という名前のシートがある
- そのシートの C3 セルに顧客名が入っている
- ファイルがマクロ有効ブック(.xlsm)としてパソコン内のフォルダに保存されている(PDFはこのファイルと同じ場所に作られます)
見積書テンプレートのシート(転記マクロ実行後)

このシートは、無料配布している【無料】Excel VBA 見積書自動作成テンプレートと同じ構成です。
手元にちょうどよいファイルが無い場合は、テンプレートをダウンロードして、この記事のコードを追加して使えます。
シート名やセル番地が違う場合は、コード中の "見積書テンプレート" と "C3" を自分のファイルに合わせて書き換えてください。
コードの貼り付け先
見積書テンプレートのシートがあるExcelファイルに、新しく標準モジュールを追加して貼り付けます。
- 見積書テンプレートのあるExcelファイルを開き、Alt+F11 でVBE(VBAを書く画面)を開く
- 左側のプロジェクトツリーで、そのファイルの「VBAProject(ファイル名.xlsm)」を右クリック→「挿入」→「標準モジュール」を選ぶ(ほかのExcelファイルを開いていると複数並ぶので、ファイル名をよく確認してください)
- 追加された標準モジュールに、下のコードを丸ごと貼り付ける
VBEの開き方や保存時の注意点は、Excel VBA初心者がまず覚えるべき基本構文まとめの「VBAを書く前の準備」で詳しく解説しています。
Excel VBAで見積書・請求書の作成を自動化する方法の転記マクロ(CreateEstimate)を使っている場合は、そのマクロが入っているのと同じExcelファイルに貼り付けます。
転記マクロで見積書を作った後にこの ExportEstimatePdf を実行すると、PDFが保存されます。
転記からPDF出力までを一度に実行したい場合は、転記マクロの中でPDFを保存している部分(savePath = ... の行から「見積書を作成しました」のメッセージの行まで)を、Call ExportEstimatePdf の1行に置き換えます。
こうすることで、転記マクロを1回実行するだけで、見積書への転記から、連番・禁止文字対策つきのPDF保存までが一度に終わります(完了時には「PDFを保存しました」と保存先が表示されます)。
Option Explicit
' 見積書テンプレートをPDF出力する(ファイル名の自動命名つき)
' ・保存先 :ブックと同じフォルダ\見積書\yyyy年mm月\
' ・ファイル名:yyyymmdd_顧客名_見積書.pdf(同名があれば _2, _3 …)
Sub ExportEstimatePdf()
Dim ws As Worksheet
Dim wbPath As String
Dim saveFolder As String
Dim customerName As String
Dim baseName As String
Dim pdfPath As String
On Error GoTo ErrHandler
Set ws = ThisWorkbook.Worksheets("見積書テンプレート")
' 1. 保存先チェック(OneDrive/SharePoint上で開いているとパスがURL形式になり、
' Dir/MkDir/PDF出力が実行時エラー52で止まるため)
wbPath = ThisWorkbook.Path
If wbPath = "" Or Left(wbPath, 4) = "http" Then
MsgBox "このファイルはOneDrive/SharePoint上で開かれているか、未保存の状態です。" & vbCrLf & _
"一度ローカルフォルダ(例:C:\見積書)にコピーして保存してから実行してください。", vbCritical
Exit Sub
End If
' 2. 顧客名を取得し、ファイル名に使えない文字を置き換える
customerName = SanitizeFileName(ws.Range("C3").Value)
If customerName = "" Then
MsgBox "見積書に顧客名が入っていません。先に転記マクロを実行してください。", vbExclamation
Exit Sub
End If
' 3. 保存先フォルダを用意する(MkDirは1階層ずつしか作れないので2段階に分ける)
saveFolder = wbPath & "\見積書\"
If Dir(saveFolder, vbDirectory) = "" Then MkDir saveFolder
saveFolder = saveFolder & Format(Date, "yyyy年mm月") & "\"
If Dir(saveFolder, vbDirectory) = "" Then MkDir saveFolder
' 4. ファイル名を組み立て、同名があれば連番を付ける
baseName = Format(Date, "yyyymmdd") & "_" & customerName & "_見積書"
pdfPath = GetUniquePath(saveFolder, baseName, ".pdf")
' 5. 印刷設定:A4縦・横幅を1ページに収める
With ws.PageSetup
.PaperSize = xlPaperA4
.Orientation = xlPortrait
.Zoom = False
.FitToPagesWide = 1
.FitToPagesTall = False
End With
' 6. PDF出力(IncludeDocProperties:=False でExcelの作成者名などをPDFに引き継がない)
ws.ExportAsFixedFormat Type:=xlTypePDF, _
Filename:=pdfPath, _
Quality:=xlQualityStandard, _
IncludeDocProperties:=False, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=False
MsgBox "PDFを保存しました:" & vbCrLf & pdfPath, vbInformation
Exit Sub
ErrHandler:
MsgBox "エラーが発生しました(" & Err.Number & "):" & Err.Description, vbCritical
End Sub
' ファイル名に使えない文字を「_」に置き換え、前後の空白を取り除く
Function SanitizeFileName(ByVal s As String) As String
Dim badChars As Variant
Dim c As Variant
Dim i As Long
s = Trim(s)
' 半角の禁止文字9つを置き換える
badChars = Array("\", "/", ":", "*", "?", """", "<", ">", "|")
For Each c In badChars
s = Replace(s, c, "_")
Next c
' セル内の改行(Alt+Enter)やタブなどの制御文字(文字コード1~31)も置き換える
For i = 1 To 31
s = Replace(s, Chr(i), "_")
Next i
SanitizeFileName = s
End Function
' folderPath & baseName & ext が既に存在すれば _2, _3 … を付けて、存在しないパスを返す
Function GetUniquePath(ByVal folderPath As String, ByVal baseName As String, ByVal ext As String) As String
Dim candidate As String
Dim n As Long
candidate = folderPath & baseName & ext
n = 1
Do While Dir(candidate) <> ""
n = n + 1
candidate = folderPath & baseName & "_" & n & ext
Loop
GetUniquePath = candidate
End Function
コードのポイント
- ファイル名を作る処理は、ほかの帳票でも使い回せます。
⇒ファイル名づくりを、本体とは別の「部品」に分けているためです。
・禁止文字の置き換え:SanitizeFileName
・連番付け:GetUniquePath
請求書や納品書のマクロでも、この2つを呼び出すだけで済みます。
直すときも部品の1か所だけなので、直し漏れを防げます。
部品(Function)の書き方は、次の記事で解説しています。
→Excel VBA初心者がまず覚えるべき基本構文まとめ - PDFは年月ごとのフォルダに分けて保存され、フォルダが無ければ自動で作られます。
⇒「見積書」→「2026年10月」の順に、1階層ずつ作っているためです。
フォルダを作るMkDirは、一度に1階層しか作れません。
親フォルダが無いまま2階層を一度に作ろうとすると、
実行時エラー '76'(パスが見つかりません)で止まります。 - 同じ名前のPDFがあれば、「_2」「_3」…と空き番号で保存されます。
⇒Dirで「同じ名前のファイルがもうあるか」を確かめているためです。
あれば番号を1つ増やして、また確かめる。
これを、空き番号が見つかるまで繰り返します。
(Dirは、ファイルがあればその名前、無ければ""を返します) - 横幅がはみ出す見積書も、自動で縮小して横1ページに収まります。
⇒印刷設定を「次のページ数に合わせて印刷」にしているためです。
(Excelの「ページ設定」画面にある設定と同じものです)
コードでは、次の2行を必ずセットで書きます。
・Zoom = False:倍率指定(100%など)をやめる
・FitToPagesWide = 1:横1ページに収める
Zoom = Falseを忘れると横1ページの指定が無視され、
列幅によっては右端が2ページ目に分かれてしまいます。 - 取引先に渡すPDFに、作成者名などの個人情報が入りません。
⇒IncludeDocProperties:=Falseを付けているためです。
省略しても入らなかったのですが、
省略時の扱いは公式に書かれていないため、
確実にするためにFalseを明示しています。
マクロを実行すると、年月フォルダの中に日付・顧客名入りのPDFが保存され、同じ条件で再実行すると「_2」付きで別ファイルになります。

つまずきやすいポイントとエラー対処
| エラー・症状 | よくある原因 | 対処 |
|---|---|---|
| 実行時エラー '1004'(ドキュメントを保存できませんでした) | ①同名のPDFを開いたまま ②ファイル名に禁止文字や改行が入っている ③保存先フォルダが無い | ①PDFを閉じる(連番方式なら開いたままでも別名で保存される) ②SanitizeFileName を通す ③ Dir+MkDir でフォルダを先に作る |
| 実行時エラー '76'(パスが見つかりません) | MkDir で親フォルダが無いのに子フォルダを作ろうとした | 1階層ずつ作る(サンプルコードの手順3) |
| 実行時エラー '52'(ファイル名または番号が不正です) | OneDrive/SharePoint上で開いていて ThisWorkbook.Path がURL形式 | ローカルフォルダにコピーして実行(詳細はExcel VBAで見積書・請求書の作成を自動化する方法の「つまずきやすいポイント」) |
| PDFが2ページに割れる・右端が切れる | PageSetup の指定漏れ、印刷範囲の設定ミス | Zoom = False と FitToPagesWide = 1 をセットで指定。印刷範囲(PrintArea)を見積書の範囲に設定 |
| PDFのプロパティに個人名が入っている | IncludeDocProperties:=True を指定している、または SaveAs でPDFにしている | ExportAsFixedFormat で IncludeDocProperties:=False を指定する。確認は、PDFをAcrobat Readerなどで開き、Ctrl+D(文書のプロパティ)で作成者欄を見る |
応用
複数シートを1つのPDFにまとめる
見積書と一緒に、作業ごとの工数などを書いた「内訳書」も渡したいことがあります。
PDFを2つ添付するより、1つのPDF(1ページ目=見積書、2ページ目=内訳)にまとめたほうが、相手も確認しやすくなります。
ここでは上のコードを書き換えて、「内訳」という名前のシートがあれば、見積書の後ろに付けて1つのPDFにするようにします。
内訳シートが無いときは、これまでどおり見積書だけを出力します。
| 内訳シート | 出力されるPDF |
|---|---|
| ある | 1ページ目が見積書、2ページ目が内訳 |
| ない | 見積書だけの1ページ(これまでと同じ) |
手順1:内訳シートを用意する
- 「見積書テンプレート」のシートを開いた状態で、画面下のシート見出しの右にある「+」を押す(見積書テンプレートのすぐ右に、新しいシートができます)
- 新しいシートの見出しをダブルクリックし、名前を「内訳」に変える
- 内訳の内容を書く(書き方は自由です)

もともとある「入力」シートの名前を「内訳」に変えて使うのはやめてください。
転記マクロ(CreateEstimate)は「入力」シートからデータを読むため、名前を変えると転記マクロがエラーで止まるようになります。
手順2:コードを書き換える
上のサンプルコードの ExportEstimatePdf の中で、「' 6. PDF出力」のコメント行から OpenAfterPublish:=False の行までの7行を、次のコードに置き換えます。
保存先フォルダの作成やファイル名の連番は、そのまま使えます。
' 6. PDF出力
' 「内訳」シートがあれば見積書の後ろに付けて1つのPDFに、無ければ見積書だけを出力する
Const DETAIL_SHEET_NAME As String = "内訳" ' 一緒にまとめるシートの名前
Dim detailWs As Worksheet
On Error Resume Next ' シートが無いときのエラーを一時的に無視する
Set detailWs = ThisWorkbook.Worksheets(DETAIL_SHEET_NAME)
On Error GoTo ErrHandler ' エラー処理を元に戻す
ThisWorkbook.Activate
If detailWs Is Nothing Then
ws.Select
Else
' PDFのページ順はシートタブの並び順になるので、内訳シートを見積書より右へ移す
If detailWs.Index < ws.Index Then detailWs.Move After:=ws
' 内訳シートも見積書と同じくA4縦・横1ページに収める
With detailWs.PageSetup
.PaperSize = xlPaperA4
.Orientation = xlPortrait
.Zoom = False
.FitToPagesWide = 1
.FitToPagesTall = False
End With
ThisWorkbook.Worksheets(Array(ws.Name, detailWs.Name)).Select
End If
' 選択中のシート(1枚または2枚)をまとめてPDFにする
' IncludeDocProperties:=False でExcelの作成者名などをPDFに引き継がない
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, _
Filename:=pdfPath, _
Quality:=xlQualityStandard, _
IncludeDocProperties:=False, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=False
ws.Select ' シートの同時選択を解除する
コードのポイント
- 内訳シートが無くてもエラーになりません。
⇒無い名前のシートを指定すると、本来はエラー9(インデックスが有効範囲にありません)で止まります。
そこでOn Error Resume Nextでこの1行だけエラーを無視し、
シートを取り出せたかどうか(Nothingかどうか)で、内訳シートの有無を判定しています。 - 内訳シートの位置を気にしなくても、見積書が1ページ目になります。
⇒PDFのページ順は、コードに書いた順ではなく、シート見出しの並び順で決まります。
内訳シートが見積書より左にあると、内訳が1ページ目になってしまうため、
コードで内訳シートを見積書のすぐ右へ移してから出力しています。 - 内訳シートもA4縦・横1ページに収まります。
⇒手順5の印刷設定と同じ内容を、内訳シートにもかけているためです。 - 「内訳」以外の名前のシートをまとめたいときは、1か所直すだけです。
⇒DETAIL_SHEET_NAMEの"内訳"を、まとめたいシートの名前に書き換えてください。
出力したPDFをその場で開いて確認する
1件ずつ内容を確認しながら出す運用なら、OpenAfterPublish:=True にすると保存直後にPDFが開きます。まとめて何件も出すときは False に戻してください。
自分の帳票に合わせて改造する
顧客名のセル番地(今回は C3)や帳票名(「見積書」)は、自分のテンプレートに合わせて書き換えてください。書き換え方が分からない場合は、このコードを丸ごと渡して「顧客名のセルをB2に、帳票名を請求書に変えて」と頼む方法をChatGPTにVBAコードを書かせて業務を自動化する方法で紹介しています。
テンプレートを無料配布しています
この記事の「前提とするExcelファイル」と同じ構成の見積書自動作成テンプレートを、無料で配布しています。
入力シートに顧客名と明細を入れてマクロを実行すると、見積書への転記からPDF保存までを自動で行えます。
テンプレートのPDF出力は、冒頭で紹介した「1行版」のままです。
この記事のコードを追加すれば、連番・禁止文字対策・年月フォルダ分けつきのPDF出力に変えられます。
まとめ
VBAのPDF出力は、ExportAsFixedFormat の1行で動かすところまでは簡単ですが、実務で使うには「ファイル名」の設計が要になります。
- ファイル名は部品で作る:禁止文字の置き換えと連番付けを本体とは別の部品(
Function)に分け、帳票が増えても使い回す - 保存前に同名ファイルを確認する:上書き確認ではなく連番にして、前回分を消さない
- 年月ごとのフォルダに分ける:PDFが増えても、月ごとにまとまって探しやすい
あわせて、IncludeDocProperties:=False で作成者名などをPDFに入れない設定を明示しておくと安心です。
転記からPDF出力までの全体像はExcel VBAで見積書・請求書の作成を自動化する方法で解説しています。この記事のコードは、その記事のマクロにそのまま追加できます。