バッチや JScript に PowerShell を埋め込んでダブルクリックで起動する Polyglot 色々

本記事は、 シェルスクリプト&PowerShell Advent Calendar 2024 2日目の記事だ。
まだまだ始まったばかり。 執筆者求む、執筆者!


さて、 PowerShell スクリプトファイル (.ps1) は、 WSH や Office VBA のウイルス蔓延を許した反省からか、 Windows の標準ではスクリプトファイルをダブルクリックしても実行できない。
ただ、これだと人にファイルを渡して実行してもらうのに手間がかかるので、特別な関連付け設定をせずダブルクリックで実行できる PowerShell スクリプトを作りたい。

ひとつのスクリプトファイルを、異なる複数のプログラミング言語で正しく解釈できるように書く、 Polyglot というテクニックがある。
そういったテクを活用して、「ダブルクリックで起動できるバッチやスクリプトを使って、自分自身を PowerShell スクリプトと解釈させて実行」する単一ファイルを作成する方法をいくつか考えてみよう。

仕組み上、 PowerShell スクリプトファイル (.ps1) を介さないので、以下のような制限がある。

  • 標準入力を受け付けられない (パイプ先になれない)
  • PowerShell 的にはスクリプトファイルを実行しているわけではないので、 $PSScriptRoot, $PSCommandPath, $MyInvocation.MyCommand.Path あたりが空になる

このため以降で紹介するどのパターンでも、自身のファイルのフルパスを環境変数 SCRIPT_PATH に入れてから PowerShell を呼び出している。
PowerShell スクリプト内では $env:SCRIPT_PATH を呼び出すことで、少なくとも後者の問題については回避できる。

コンソールウィンドウありバッチファイル

続きを読む

VBA / VBS で正規表現による関数を使った置き換え

JScriptのString.replaceメソッドは非常に便利だ。
置き換え文字列に、「文字列」ではなく「関数」が使えるところが意外と使える。

"test0 test1".replace(
    /\w+(\d)/g,
    function($0,$1){return (Number($1)+1).toString();})

てな具合に。

普段はWSHではVBSなんぞ使ったりしないが、
たまにどうしてもVBAやVBSを使わなくてはならない場合がある。
そんなときにそれっぽい動作をする様なのを、
不完全ながら自作してみた。

続きを読む

WSHで強制的にcscriptで起動させつつエラーは出す

JScriptで、ダブルクリックしたときにコマンドプロンプトで強制的に起動するとき
こんな感じで起動してやると、
Echoがたくさんあっても大変なことにならず、
しかもエラーコードもしっかり返すことができる。

function CRun(){
    if (!(/CSCRIPT\.EXE/i).test(WScript.FullName)){
        var WshShell = new ActiveXObject("WScript.Shell");
        var strParam = "";
        for (var i = 0; i < WScript.Arguments.Count(); i++){
            strParam += " \"" + WScript.Arguments(i).replace("\"", "\"\"") + "\"";
        }
        WScript.Quit(WshShell.Run("cmd.exe /v:on /s /c \"cscript.exe //nologo \""
            + WScript.ScriptFullName + "\"" 
            + strParam + " & pause & exit /b !ERRORLEVEL!\"", 8, true));
    }
}
CRun();
WScript.Echo("CScript!");
WScript.Quit(8);

環境変数の遅延展開をつかって、ERRORLEVELを戻しているのがミソ。
これで、エラーが起きたときの処理もできる。
私は業務を軽減するツールとか作るときに割とよく使う。