日常のスクリプト言語にJavaScriptはいかが?

JavaScript Advent Calender の14日を担当させていただきます。よろしくお願いします。


ところでみなさん、最近特に話題になっているあの言語、なんだかご存知ですよね?


そう、みなさん大好きなあの言語の名前は何でしょう!?



・・

・・・


『そうだね、JScript だね!』



はい、すみません。ごめんなさい。
というわけで(どういうわけで?)、ぼくの担当分は日常的にちょっと作業をする際の言語としてのJavaScriptをご紹介したいと思います。
今回はあえてWindows環境のみの紹介なので、JScriptといったほうが良さそうです。


ちょっとした作業で使うにはあまり便利とはいえませんが、もしかしたらこんな状況があるかも知れません。

  • Javaと聞いていたのに、行ってみたらCOBOLだった
  • PCには好きにソフトをインストールできない(業務規則的に)
  • というかそもそもネットワークにつながっていない(機密保持的に)
  • 使用してよいのはWindowsのみである


いやいや、ないとは言い切れませんよね!?
あぁ、恐ろしい。。。


そんなとき、ちょっとした作業に使える言語といえばMicrosoftが標準でサポートしている言語に限られてきてしまいます。
そうなったら、きっとみなさん迷わずJScriptを選ぶはず(tricknotes調べ)です!


さてさて、それではさっそく。


Windows Vista以降では、UACによってあらゆる操作が禁止されてしまいます。
『トイレの水を流そうとすると「本当に流しますか?」と聞いてくる』という有名なギャグがあるほどに。

そこでまずは管理者権限でJScriptを実行するところから。

(function() {
    // UACの識別に使用
    var key = "__uac";
    var args = WScript.Arguments;
    var length = args.length;
    
    var lastArg;
    if (length !== 0) {
        lastArg = args(length - 1);
    }

    if(key !== lastArg) {
        // 引数の引き回し用の配列
        var newArgs = [];
        for (var i = 0; i < length; i++) {
            newArgs.push(args(i));
        }
        // 識別用のキーを付与
        newArgs.push(key);
        
        // 元からの引数を引き継いで実行
        var sh = WScript.CreateObject("Shell.Application");
        sh.ShellExecute("wscript.exe", "\"" + WScript.ScriptFullName + "\" " + newArgs.join(" "), "", "runas", 1);
        // 初回の実行終了する
        WScript.Quit(0);
    }
})();

こちらを参考にさせていただきました。


これをjsファイルの先頭に記述しておくと、スクリプト実行時に管理者権限を与えるかの確認を求められます。
これでJScriptで何でもやりたい放題できる許可をもらいます。

うーん、スクリプト内で管理者権限で実行中かどうかを判断する方法って何かいいのがありますかねぇ。

スクリプト実行時の引数を取得するのがArgument関数となっているところに注意です。
(ちなみに存在しない引数にアクセスしようとすると例外が発生します)


また当然のように、CommonJSの仕様に準拠しているはずなどありません。
でもスクリプトが大きくなってくると、ファイルを分割したくなってくると思います。


しかし幸いながら、JScriptでローカルのファイルを読むことができます。
それならもう怖いものはありません。
evalでしのぎます。

function require(filepath) {

    var fs = new ActiveXObject("Scripting.FileSystemObject");
    var __dirname = WScript.ScriptFullName.replace(WScript.ScriptName, "");
    
    var file = fs.OpenTextFile(__dirname + filepath);

    var module = (function() {
        var module = {exports: {}};

        var source = [];
        while (!file.AtEndOfStream) {
            source.push(file.ReadLine());
        }

        eval(source.join("\n"));

        return module 
    })();

    return module.exports;
}

かなり力技ですが、node.jsっぽく外部ファイルを読み込むことができます。
(読み込まれる側のファイルの中から、一部の変数が見えてしまっていますが。。。)


例えば以下のようなファイルを用意します。

// demo.js
module.exports.hello = function() {
    return "hello world";
}

起動スクリプトから、以下のようにして呼んでやります。

var demo = require("demo.js");
demo.hello(); // "hello world"


さて、WindowsといえばExcel、ExcelといえばWindows。
ということでExcelもJScriptから記入してみましょう。

// エクセルファイル名
var filename = "demo.xls";

try {
    var excel = new ActiveXObject("Excel.Application");
    // エクセルファイルが画面に表示しない
    excel.Visible = false;
    // 確認ダイアログを表示しない
    excel.DisplayAlerts = false;

    try {
        // ファイルを開く
        var workbook = excel.Workbooks.Open(__dirname + filename);

        // ワークシートを取得
        var worksheet = workbook.Worksheets(1); // シート名でも指定できる

        var today = new Date();

        // 指定したセルへ値を設定

        // 日付を設定
        worksheet.Cells(1, 1).value = String(today.getYear()) + "年" + String(today.getMonth() + 1) + "月" + String(today.getDate()) + "日";

        // 名前を設定
        worksheet.Cells(2, 1).value = "tricknotes";

        // ファイルを保存
        worksheet.Save();
        
    } finally {
        // 後始末をしておかないとプロセスが残る
        if (workbook) {
            workbook.Close();
        }
    }
} finally {
    // 後始末をしておかないとプロセスが残る
    if (excel) {
        excel.Quit();
    }
}

Openメソッドの引数の説明はこちら


ちなみに、新規に作成する場合はこんな感じです。

var filename = "new_book.xls";

// 新規にワークブックを作成
var workbook = excel.Workbooks.Add();

try {
    var worksheet = workbook.Worksheets(1);
    worksheet.Cells(1, 1).value = "This file is created by JScript.";

    // ファイルを新規保存
    workbook.SaveAs(__dirname + filename);

} finally {
    workbook.Close();
}

この他にも、HTTPリクエストを発行したり、レジストリから値を取得したりと、わりと好き放題できます。
JScriptが何でもできるというよりは、ActiveXObjectをJScriptから使えていると表現した方がいいのかもしれません。
Windowsだけとはいえ、OS標準のシェルとしては十分魅力的な機能を備えていると思います。


JScriptを最優先で使おうとは思いませんが、Windows環境の特別な場合には選択肢の1としてアリかな、と思います。