Windows上で複数シートから成るExcelファイル、 Wordファイルを簡単にPDF化するツールを作ってみた

# 概要
大量のシートから成るExcelファイルを一気にPDF化出来るツールを作りたいと思い、調べてみたら良さそうな記事をネットで見つけました。そのままでも十分使える機能を備えていますが、エラーハンドリングや保存ディレクトリの作成機能など、幾つか改良点を見出したので、自分なりに改良を加えたツールを完成させました。

# 事の起こり
筆者の父親から大量のシートから成るExcelファイルをPDF化する方法について相談を受けました。筆者自身の環境であれば、Pythonなどのプログラミング言語の開発環境を駆使してツールを作るところですが、父親のPCに開発環境を入れる訳にもいきません。。。よって、インストール作業などが不要で、なおかつ簡単に使えるツールを作ることにしました。調べてみたところ、WindowsにはJScriptというMicrosoftが開発したJavaScriptライクな言語がデフォルトでインストールされているため、これを活用すれば出来そうです。

:warning: PowerShellでも同様のことが出来ると思われますが、筆者は宗教上の理由でPowerShellは使わないため、JScriptで実装しました。

:warning: 本来はモジュール毎にソースファイルを分けるべきかもしれませんが、利用される環境の事情を考慮して1つのソースファイルにまとめて実装することにしました。

# Excel to PDFツール
以下のWebページでExcelファイルをPDF化するツールの作り方が掲載されています。

https://skainoblog.com/sheet-pdf-change/

:warning: JScriptでツールを作る時は、文字コードをShift-JIS(ANSI)に設定する必要が有ります。

# 改良案
* 自動的にファイル名からディレクトリを作成し、その中にPDFファイルを格納する
* エラーハンドリング
* リファクタリング

# 改良版ソース
上記改良案を反映したソースが以下です。

```js
// ExcelファイルをPDFに変換する
function ExportPDF(fname) {
    var fs = new ActiveXObject("Scripting.FileSystemObject");

    // フォルダパスを取得
    var parentPath = fs.GetFile(WScript.ScriptFullName).ParentFolder

    // ファイル名を取得
    var fileName = fs.GetBaseName(fname);
    var folderName = fileName;

    // 出力フォルダ名を設定
    var outputPath = parentPath + "/" + folderName;

    if(fs.FolderExists(outputPath)) {
        WScript.Echo(folderName + "は既に存在します");
        WScript.Quit();
    } else {
        fs.CreateFolder(outputPath);
    }

    // 出力先、ファイル名を設定
    var output = outputPath + "/" + fileName;

    // Excelを開き、PDFに変換する
    var book = excel.Workbooks.Open(fname);
    var sheets = book.worksheets;
  
    for (var i = 1; i <= sheets.Count; i++) {
        // シート名を取得
        var sheetName = sheets(i).name;
        // PDFファイル名を設定
        var pdfFileName = output + "_" + sheetName;
        try {
            sheets(i).ExportAsFixedFormat(0, pdfFileName, 0, true, false);
        } catch(e) {
            WScript.Echo("ファイルが壊れているか、変換対象が存在しません");
            book.Close();
            excel.Quit();
            fs.DeleteFolder(outputPath, true);
            WScript.Quit();
        }
    }
    book.Close();
}

// ドラッグ&ドロップされたファイルを確認する
if (WScript.Arguments.Count() == 0) {
    WScript.echo("ファイルがありません");
    WScript.Quit();
}

// Excelを起動する
var excel = WScript.CreateObject("Excel.Application");
excel.Visible = true;

// 1ファイルずつPDFに変換する
for (var i = 0; i < WScript.Arguments.Count(); i++) {
    ExportPDF(WScript.Arguments.Item(i));
}
excel.Quit();
WScript.echo("変換完了");
```

# 更に改良版
* Wordファイルにも対応(拡張子で判定)

```js
function ExcelToPDF(fname, fs) {
    // ファイル名を取得
    var fileName = fs.GetBaseName(fname);
    var folderName = fileName;

    // フォルダパスを取得
    var parentPath = fs.GetFile(WScript.ScriptFullName).ParentFolder

    // 出力フォルダ名を設定
    var outputFolder = parentPath + "/" + folderName;

    if(fs.FolderExists(outputFolder)) {
        WScript.Echo(folderName + "は既に存在します");
        WScript.Quit();
    } else {
        fs.CreateFolder(outputFolder);
    }

    // 出力先、ファイル名を設定
    var outputPath = outputFolder + "/" + fileName;

    // Excelを起動する
    var excel = WScript.CreateObject("Excel.Application");
    excel.Visible = true;

    // Excelを開き、PDFに変換する
    var book = excel.Workbooks.Open(fname);
    var sheets = book.worksheets;
  
    for (var i = 1; i <= sheets.Count; i++) {
        // シート名を取得
        var sheetName = sheets(i).name;
        // PDFファイル名を設定
        var pdfFileName = outputPath + "_" + sheetName;
        try {
            sheets(i).ExportAsFixedFormat(0, pdfFileName, 0, true, false);
        } catch(e) {
            WScript.Echo("ファイルが壊れているか、変換対象が存在しません");
            book.Close();
            excel.Quit();
            fs.DeleteFolder(outputFolder, true);
            WScript.Quit();
        }
    }
    book.Close();
    excel.Quit();
}

function WordToPDF(fname, fs) {

    // ファイル名を取得
    var fileName = fs.GetBaseName(fname);
    var folderName = fileName;

    // フォルダパスを取得
    var parentPath = fs.GetFile(WScript.ScriptFullName).ParentFolder

    // 出力フォルダ名を設定
    var outputFolder = parentPath + "/" + folderName;

    if(fs.FolderExists(outputFolder)) {
        WScript.Echo(folderName + "は既に存在します");
        WScript.Quit();
    } else {
        fs.CreateFolder(outputFolder);
    }

    // 出力先、ファイル名を設定
    var outputPath = outputFolder + "/" + fileName;

    // Wordを起動する
    var word = WScript.CreateObject("Word.Application");
    word.Visible = true;

    // Wordを開き、PDFに変換する
    var doc = word.Documents.Open(fname);
  
    try {
        doc.SaveAs(outputPath ,17);
    } catch(e) {
        WScript.Echo("ファイルが壊れているか、変換対象が存在しません");
        doc.Close();
        word.Quit();
        fs.DeleteFolder(outputFolder, true);
        WScript.Quit();
    }
    doc.Close();
    word.Quit();
}

// Excel, WordファイルをPDFに変換する
function ExportPDF(fname) {
    var fs = new ActiveXObject("Scripting.FileSystemObject");

    // 拡張子を取得
    var exts = fs.GetExtensionName(fname);

    if (exts === "xlsx") {
        ExcelToPDF(fname, fs);
    } else if (exts === "docx") {
        WordToPDF(fname, fs);
    } else {
        WScript.Echo("ファイル形式が不正です");
        WScript.Quit();
    }

}

// ドラッグ&ドロップされたファイルを確認する
if (WScript.Arguments.Count() == 0) {
    WScript.echo("ファイルがありません");
    WScript.Quit();
}


// 1ファイルずつPDFに変換する
for (var i = 0; i < WScript.Arguments.Count(); i++) {
    ExportPDF(WScript.Arguments.Item(i));
}

WScript.echo("変換完了");
```

# まとめ
無事ツールが完成しました。これで複数のExcelファイル、WordファイルのPDF化を簡単かつ高速に手間無く実現出来ました。

# Reference
https://skainoblog.com/sheet-pdf-change/

https://jscript.zouri.jp/Source/FileFolderCtrl.html

https://qiita.com/tnakagawa/items/6c468ee355eb9f7c0664

https://cartman0.hatenablog.com/entry/2016/01/07/003032

https://www2f.biglobe.ne.jp/takan/javac/js/wsh/obj_fso.htm