バッチファイルから PowerShell を呼び出す方法

  • 60
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

背景

PowerShell でスクリプトを書くメリットの一つとしては、Windows7 以降ならデフォルトで入っているので、Windows を使っている人になら書いたスクリプトを渡して、そのまま使えることにあると思っている。(しかも .NET が使える)
ただデフォルトの設定だと PowerShell のスクリプトを実行できなかったり、ダブルクリックで実行できないのも、ちょっと不便だなと感じるので、その回避方法をメモする。

普通に引数で渡す

一番単純な方法は、PowerShell のスクリプトを呼び出すバッチファイルを、いっしょに置いておくことだと思う。
デフォルトだと ExecutionPolicy の値でスクリプトの実行ができないのでオプションで指定する。

hello.bat
powershell -NoProfile -ExecutionPolicy Unrestricted .\hello.ps1
hello.ps1
Write-Host "Hello, World!!"

ただちょっとした処理を書くために使いたいケースが多いのに、ファイルが 2 つに分かれてしまうのは、ちょっと嫌だなと感じる。

一行だけなら、こうも書ける

powershell -NoProfile -ExecutionPolicy Unrestricted -Command "& { echo 'Hello, World!!' }"

ただこれで書くと、少し量が増えただけでゴチャゴチャする。

1 つのファイルにまとめる

これが今回メモしておこうと思った内容。
最近、Scala を使いだしたら、Scala だとバッチファイルに、

::#!
@echo off
call scala %0 %*
goto :eof
::!#

println("Hello, World!!")

とか書くと、Scala がインストールされている環境なら動いてしまう。
これがなぜ動くを、よく見てみると PowerShell でもできるのではないかと思った。
ググってみると、 stackoverflow に説明してあるのがあった。
さらにググってみると、 Make it easier to wrap powershell scripts in batch files というのを見つけた。

@powershell -NoProfile -ExecutionPolicy Unrestricted "$s=[scriptblock]::create((gc \"%~f0\"|?{$_.readcount -gt 1})-join\"`n\");&$s" %*&goto:eof

Write-Host "Hello, World!!"

とりあえず、これで動くらしい。というか動く。
やってることは、両方ともバッチファイルの中で自分自身を呼び出して、その呼び出す記述を呼び出す側で無視するという感じ。

これなら多少コードが増えても、そこそこ使える気がする。

Base64 encode

ついでに、Base64 encode するというのもあった。
ちょっと面倒な気もするけど、これはこれで何かに使えるかもしれない。

powershell -NoProfile -ExecutionPolicy Unrestricted -EncodedCommand ZQBjAGgAbwAgACIAaABlAGwAbABvACIAOwAgAGUAYwBoAG8AIAAiAHcAbwByAGwAZAAiADsA

エンコードする PowerShell ワンライナー

# 文字コードは適宜調整すること
# 元にする PowerShell のコードは行末に ; を付けること
"powershell -NoProfile -ExecutionPolicy Unrestricted -EncodedCommand $([Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($(cat .\hello.ps1))))" | Out-File .\base64encoded.bat -Encoding Default