2
3

More than 3 years have passed since last update.

WSHでES2015を利用するベストプラクティス

Last updated at Posted at 2021-05-28

Qiita初投稿です。

概要

Windows Script Host(WSH)はWindowsに標準搭載されたスクリプト実行環境です。
心臓部にEdge(Legacy)に搭載されたJavaScriptエンジンであるChakraを利用することで、ES2015相当の言語機能を利用することができます。

Chakraを常用するベストプラクティスを探っています。

  • CLSIDは覚えられない
  • 職場など管理者権限のない環境でも設定できる
  • 他人の環境でも動く
  • ダブルクリックで実行できるWSHの利点を損ないたくない
  • 将来的にTypeScriptで書きたい

など...

環境

  • Windows10

私の環境で試していること

この記事のコードは、GitHubに置いています。

バッチにPATHを通す

以下3つのバッチファイルを作成し、PATHを通します。
WChakra.bat, CChakra.batはそれぞれwscript, cscriptを司り、Chakra.batはデフォルトがどちらか調査して適当に振り分けます。
コマンドラインからchakra hoge.js wchakra fuga.jsなどで利用できるほか、既定のアプリケーションに登録することもできます。

良いところ

  • 特にコンソールから実行する場合にわかりやすい
  • 拡張子に関連付けして、ダブルクリックで実行できる

微妙なところ

  • バッチは普段書かないので改善点があるかも(逐次修正)
  • Chakra.batはほんの少し遅いので、大量にキックする用途だと厳しそう
  • WChakra.batをダブルクリックで実行中にはDOS窓が表示される
Chakra.bat
@echo off
setlocal
set fn=%~dp0\_.vbs

REM this one-liner returns 0 only if hosted by "wscript.exe"
echo If(LCase(WScript.CreateObject("Scripting.FileSystemObject").GetFileName(WScript.FullName))="wscript.exe")Then:ret=0:Else:ret=1:WScript.Quit(ret) > %fn%
%fn% > nul 2>&1

if %errorlevel% equ 0 (
    del %fn%
    WChakra %*
) else (
    del %fn%
    CChakra %*
)
exit /b %errorlevel%
WChakra.bat
@echo off
if not "%~1"=="" (
    wscript //E:{1B7CD997-E5FF-4932-A7A6-2A9E636DA385} %*
) else (
    wscript
)
exit /b %errorlevel%
CChakra.bat
@echo off
if not "%~1"=="" (
    cscript //E:{1B7CD997-E5FF-4932-A7A6-2A9E636DA385} %*
) else (
    cscript
)
exit /b %errorlevel%

冒頭に「おまじない」を書く

こちらを参考にさせていただきました。
ダブルクリックまたはドラッグアンドドロップで利用できます。

変更点

  • 文字数を絞る
  • 生成される一時ファイルを隠しファイルに変更
  • コマンドライン引数対応
  • WScriptとCScriptを判別してキック

良いところ

  • 冒頭(と末尾)に記載するだけ、手軽
  • 他人の環境でも動く

微妙なところ

  • 現状CScriptの標準入力は利用できない
args.js
/*@cc_on
w=WScript;
st=w.CreateObject("ADODB.Stream");
fs=w.CreateObject("Scripting.FileSystemObject");
sh=w.CreateObject("WScript.Shell");
fn=w.ScriptFullName;

// 自身の文字コードをShift-JISに変換した一時ファイルを作成する
st.Charset="UTF-8";
st.Open();
st.LoadFromFile(fn);
t=st.ReadText();
st.Close();
fn=fs.GetFile(fn).ParentFolder.Path+"\\."+w.ScriptName;
if(fs.FileExists(fn))fs.DeleteFile(fn,true);
st=fs.CreateTextFile(fn);
f=fs.GetFile(fn);
f.Attributes=2;
st.Write(t);
st.Close();

// コマンドライン引数を引き継ぐ
arg=w.Arguments;
opt="";
for(i=0;i<arg.Count();i++){
    opt+=" \""+arg.Item(i)+"\"";
}
opt=opt.slice(1);

// キック
host=w.FullName;
cmd=host+" //Nologo //E:{1B7CD997-E5FF-4932-A7A6-2A9E636DA385} \""+fn+"\" "+opt;
if(fs.GetFileName(host).toLowerCase()=="wscript.exe"){
    ret=sh.Run(cmd,1,true);
}else{
    ex=sh.Exec(cmd);
    while(ex.Status==0){
        try{
            w.StdOut.Write(ex.StdOut.Read(1));
        }catch(e){}
    }
    ret=ex.ExitCode;
    w.StdOut.Write(ex.StdOut.ReadAll());
}
f.Delete(true);
w.Quit(ret);
@if(0)*/

// 本体ここから
const args = WScript.Arguments;
let msg = "";
for(let i = 0; i < args.Count(); i++){
    msg += `${args.Item(i)}\n`;
}
WScript.Echo(msg);

//@end
omajinai.js
/*@cc_on;w=WScript;st=w.CreateObject("ADODB.Stream");fs=w.CreateObject("Scripting.FileSystemObject");sh=w.CreateObject("WScript.Shell");fn=w.ScriptFullName;st.Charset="UTF-8";st.Open();st.LoadFromFile(fn);t=st.ReadText();st.Close();fn=fs.GetFile(fn).ParentFolder.Path+"\\."+w.ScriptName;if(fs.FileExists(fn))fs.DeleteFile(fn,true);st=fs.CreateTextFile(fn);f=fs.GetFile(fn);f.Attributes=2;st.Write(t);st.Close();arg=w.Arguments;opt="";for(i=0;i<arg.Count();i++){opt+=" \""+arg.Item(i)+"\"";}opt=opt.slice(1);host=w.FullName;cmd=host+" //Nologo //E:{1B7CD997-E5FF-4932-A7A6-2A9E636DA385} \""+fn+"\" "+opt;if(fs.GetFileName(host).toLowerCase()=="wscript.exe"){ret=sh.Run(cmd,1,true);}else{ex=sh.Exec(cmd);while(ex.Status==0){try{w.StdOut.Write(ex.StdOut.Read(1));}catch(e){}}ret=ex.ExitCode;w.StdOut.Write(ex.StdOut.ReadAll());}f.Delete(true);w.Quit(ret);@if(0)*/

レジストリを編集する

こちらを参考にさせていただきました。
wscript //E:Chakra hoge.jsで利用できるようになります。

良いところ

  • wsfでも利用できる(はず、確認出来たら追記)
    • CLSID直書きでもできるかも

微妙なところ

  • 他所の環境では動かない
  • レジストリいじるときは慎重に
HKCR.reg
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Chakra]
@="Chakra Language"

[HKEY_CLASSES_ROOT\Chakra\CLSID]
@="{1b7cd997-e5ff-4932-a7a6-2a9e636da385}"


HKCU.reg
Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\SOFTWARE\Classes\Chakra]
@="Chakra Language"

[HKEY_CURRENT_USER\SOFTWARE\Classes\Chakra\CLSID]
@="{1b7cd997-e5ff-4932-a7a6-2a9e636da385}"


機能制限について補足

Chakra利用時にWScript.Quit()が利用できないため、終了コードを返せないとのことなので実験しました。
1~6の整数を終了コードにセットするJavaScriptを用意して、10回実行します。
PowerShellでは、$LastExitCodeに直前の終了コードが代入されます。

エラーが発生するため、握り潰します。

dice.js
try {
    WScript.Quit(parseInt(6 * Math.random() + 1));
} catch (e) {
    // JavaScript runtime error: Object doesn't support this action
}
PowerShell
> for($i=0; $i -lt 10; $i++){chakra dice.js; echo $LastExitCode;}
1
4
5
6
5
2
4
1
3
2

きちんとランダムです。
エラーが発生し停止もしませんが、なぜか終了コードは返せているようです。

参考

随時更新...

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3