Powershell で作ったツールを簡単に配布してダブルクリックで起動したい
昔(20年くらい?)から私はWSH(VBScript)をよく使っていたのですが、最近の若い者から「今はPowershellですよ。VBScriptなんて、もうすぐ無くなりますよ」と年寄り扱いされたので、去年からPowerShellを使うようになりました。
使ってみるとpowershell は強力なんだけど ps1 ファイルを配布しただけでは、ダブルクリックしても起動しないので、ツールとしては不便を感じていました。
いろいろやってみて WSH(VBScript) みたいにツール単体を配布するだけで簡単に起動できるものが出来たので、投稿します。
.bat にすることで起動方法のバリエーションが増えるので、ツールとしての利便性が格段に上がります。
是非お試しください。
私は powershell で作ったツールは全部この方法で起動してます。一度使ったら止められません。
なお、一回作ったものに機能追加するときは、一旦 .ps1 に変更して ISE でコーディング/デバッグしてから .bat に戻してます。
.ps1 で編集して出来上がったら、.bat をハードリンクで作成しておくと、実行時は .bat 編集時は .ps1 としてエディタで編集できるので便利です。
作り方
- powershell を普通に(Windows Powershell ISE などで).ps1 で作ります。
- パラメータで渡したいものは、変数 $parm[0..8] にセットされている前提で作ってください。
- 以下の HelloWorld.bat の最後の1行(Write-Host の行)以外の部分を .ps1 の頭の部分に挿入します
- ファイル名を .bat に変更します
- ファイルをメモ帳で開いてみて UTF-8 だった場合は、ANSI (Shift_JIS) で保存しなおします。
- 実行用の.bat をハードリンクで作ります。=> DOS 窓を管理者権限で開いて、mklink /H xxxxxx.bat xxxxxx.ps1
:DUMMY for($i=1;$i -eq 0;$i++) {echo DUMMY} <#
@rem 上の行は batでは(goto されない)ラベル。
@rem パワーシェルでは(条件は常にfalseで実行されない)ラベル付きfor
@rem bat でも パワーシェルでもエラーにならずに、パワーシェルにとってのコメントブロックを開始。
@rem 2行目以降は bat を実行するエリア。パワーシェルから見れば単なるコメントブロック。
@rem /C オプションのときは bat は待たずに終了。オプションがなければ PAUSE で待つ。
@rem bat に渡された引数は、パワーシェルに$parm[0..8]で渡す。
@echo off
set ME=%~dpnx0
rem /C オプションの有無をチェック
if /i CHK%1==CHK/C (
set CHK=EXIT
shift
) else (
set CHK=PAUSE
)
rem パワーシェルを実行。自分自身をコマンドの入ったテキストとして取込んで実行。
powershell -ExecutionPolicy RemoteSigned -Command "Invoke-Expression -Command (@('$parm=@(\"%1\",\"%2\",\"%3\",\"%4\",\"%5\",\"%6\",\"%7\",\"%8\",\"%9\")') + (Get-Content '%ME%') -join \"`n\")"
if /i %CHK%==EXIT exit /b
pause
exit /b
bat のエリアは、exitまで。ここから先は(exit後なので)bat にとっては単なるゴミ #>
# ここから下はパワーシェルの領域
Write-Host "Hello World!"
.bat の中にコメント(rem 文)を入れてあります。何をやっているのかは、そちらをご覧ください。
最大のポイントは1行目。powershell のブロックコメント <# を始めたかったのですが、不用意に書くと bat でリダイレクトとして認識されてしまうので、これを避けるために工夫してます。
これ以外の書き方もあると思います。誰か、もっとカッコいい方法があったら教えてください。
パラメータ渡しのサンプル tail.bat
(長いログファイルの最後の部分だけ見たかったので作りました)
powershell へのパラメータの渡し方のサンプルとして、tailコマンドの例を以下に添付します。
サンプルでは input のファイルをパラメータとして渡してます。
tai.bat の使い方は以下の通り、いろいろな起動方法で実行できるので、ps1 より格段に便利です。
- tail.bat をダブルクリックして実行して、コマンドラインからファイル名を手で入力する
- 入力のtxtファイルをマウスでドラッグして、tail.bat の上にドロップする
- コマンドラインからコマンド入力=> [パス]tail [/C] [/N 行数] [ファイル名]
- バッチファイルの中から呼ぶ=> CALL [パス]tail.bat /C [/N 行数] ファイル名
:DUMMY for($i=1;$i -eq 0;$i++) {echo DUMMY} <#
@rem 上の行は batでは(goto されない)ラベル。パワーシェルでは(条件は常にfalseで実行されない)ラベル付きfor
@rem bat でも パワーシェルでもエラーにならずに、パワーシェルにとってのコメントブロックを開始したかっただけ。
@rem 2行目以降は bat を実行するエリア。パワーシェルから見れば単なるコメントブロック。
@rem /C オプションのときは待たずに終了。オプションがなければ PAUSE で待つ。
@rem bat に渡された引数は、パワーシェルに$parm[0..8]で渡す。
@echo off
set ME=%~dpnx0
rem /C オプションの有無をチェック
if /i CHK%1==CHK/C (
set CHK=EXIT
shift
) else (
set CHK=PAUSE
)
rem パワーシェルを実行。自分自身をコマンドの入ったテキストとして取込んで実行。
powershell -ExecutionPolicy RemoteSigned -Command "Invoke-Expression -Command (@('$parm=@(\"%1\",\"%2\",\"%3\",\"%4\",\"%5\",\"%6\",\"%7\",\"%8\",\"%9\")') + (Get-Content '%ME%') -join \"`n\")"
if /i %CHK%==EXIT exit /b
pause
exit /b
bat のエリアは、exitまで。ここから先は(exit後なので)bat にとっては単なるゴミ #>
# ここから下はパワーシェルの領域
# Write-Host "受け取ったパラメータ" ($parm[0..8] -join ", ")
# パラメータから /N スイッチをチェックして行数をセット。デフォルトは10行
$idx=0
if ($parm[$idx] -eq "/N") {
$idx++
$num=$parm[$idx]
$idx++
} else {
$num=10
}
# ファイル名を取得
if ($parm[$idx] -eq "") {
$mymsg = "`r`ntail [/C] [/N 行数] [ファイル名] : ファイルの最後のn行(デフォルト10行)を出力。/C でpauseせずに画面を閉じます`r`n`r`n"
$current=Get-Location
$mymsg = "$mymsg `r`nカレントフォルダ $current `r`n`r`n対象ファイルの PATH を入力してください"
$input = Read-Host $mymsg
} else {
$input = $parm[$idx]
}
if ($input -eq ""){
Write-Host "`r`nファイル名が空です`r`n`r`n"
exit
}
if (Test-Path $input) {
$fullpath = $input
} else {
Write-Host "`r`n$input が見つかりません`r`n`r`n"
exit
}
# ファイルの最後のn行を取得
Get-Content -Path $fullpath -Tail $num
##あとがき
昔これと同じ発想で perl を起動していました。当時は perl 結構流行ってたんですよね。最近あまり見かけませんね。
Power shell は何でもできるのは運用周りのスクリプトとして優れてますが、やっぱりとっつきにくいですよね。コマンドが独特で。
こちらのwebsiteもよろしくお願いします。
[初心者のためのWEBシステムのインフラ構築]