cmd.exeからPowerShellを実行する4の方法

GNOME Terminal

導入

コマンドプロンプト (cmd.exe) は機能が乏しく,Windowsで込み入った作業を行う場合に,PowerShellを使いたい場合がある。

しかし,PowerShellはセキュリティの設定で,デフォルトではスクリプトファイルを直接実行できない。これを実現するにはレジストリーを変更する必要がある。利用者へのレジストリー変更の強制は,スクリプトの移植性の観点から避けたい。

一方,cmd.exeからPowerShellを呼び出せば,レジストリーの変更無しでPowerShellの実行が可能となる。

そこで,cmd.exeからPowerShellを実行する4の方法を記す。

サンプルコードは「example/cmd.exe/RunPowerShell at master · senooken/example」に掲載しており,WIndows 7と10で動作を確認している。

1.コマンド引数

1番目の方法では,コマンド引数として,PowerShellのコードを指定する。

powershell ^
  $var = 'argument'; ^
  echo $var; ^

PowerShellには-Command (-c) オプションが存在しており,このオプションの後に文字列を指定すると,その文字列をPowerShellコードとして実行する。

PowerShellの文の終了は,セミコロン (;) である。そのため,実行したいコードを;で区切ってひたすら渡すことで,PowerShellのコードをcmd.exeから実行できる。

1行にひたすら書き連ねても問題ないが,可視性のため^でcmd.exeのコマンドを継続させて複数行に記載している。

なお,-Command (-c) オプションは省略しても問題なく実行できた。

PowerShellのワンライナーや数行以内のコードであれば,この方法で実行するのが手軽だろう。

2. 標準入力

2番目の方法では,標準入力を使う。

echo ^
  $var = 'stdin'; ^
  echo $var; ^
  | powershell -

PowerShellの-Commandと-Fileオプションに-を指定した場合,標準入力からデータを受け取る。

これを利用して,実行したいコードをechoコマンドで;区切りの1行のテキストとして渡すことで,PowerShellコードを実行する。

使い勝手は1番目のコマンド引数と同等だ。違いは,echoコマンドの代わりに他のコマンドを使うことで,より柔軟なデータの受け渡しが可能な点だろう。

なお,-FIleオプションも-Commandオプションと同様に,オプション指定がなくても実行できた。

3. ファイル

3番目の方法では,実行したいPowerShellコードを外部ファイルに記述しておき,そのファイルを指定して実行する。

echo $var = 'file'>>file.ps1
echo echo $var>>file.ps1
type file.ps1 | powershell -
powershell -ExecutionPolicy Unrestricted .\file.ps1
del file.ps1

3行目は標準入力経由でデータを渡している。4行目はコマンド引数にファイルを指定している。コマンド引数にファイルを指定する場合,以下の2点に注意する。

PowerShellにファイルを指定して実行する場合の注意点
  1. -ExecutionPolicy Unrestrecitedを指定
  2. ファイルを相対パスか絶対パスで指定

1点目は,PowerShellのセキュリティガードを回避するために必須となる。ファイルは相対パスか絶対パスで指定しないと,ファイルとして認識できなかった。

既存のPowerShellコードを実行するだけなので,シンプルで扱いやすい方法だ。1-2番目の方法と異なり,長く複雑なコードにも対応できる。

ただし,外部ファイルを実行するだけなので,ほとんど中身のない余計なファイルが増える欠点がある。できることならば,単独ファイルでPowerShellを実行できるとより望ましいだろう。

4. 単独ファイル

4番目の方法では,3番目の中身のほぼない余計なファイルが増える欠点を解消している。

@powershell -ExecutionPolicy Unrestricted Invoke-Expression((Get-Content "%~f0" ^| Select-Object -Skip 1) -join \"`n\") %* & exit /b
$var = 'powershell'
echo $var

この方法は,以前掲載した「シバンなしファイルでのスクリプト系言語のインタープリターの実行」と同じ方法を流用した方法だ。

1行目のコードがやや複雑なので,手順を以下で説明する。

単独ファイルでの実行方法の手順
  1. -ExecutionPolicy Unrestricted: セキュリティガードを回避。
  2. Get-Content "%~f0": 絶対パスで0番目の引数である自分自身のファイルの内容を出力。
  3. ^| Select-Object -Skip 1: ファイルの内容をパイプで受け取り,1行目をスキップして出力。
  4. -join \"`n\": 出力結果が配列になっているので,改行で結合。
  5. Invoke-Expression () %*: 1行目をスキップした文字列と引数を渡して,文字列の内容を実行。
  6. & exit /b: PowerShellの実行結果を引き継いでcmd.exeは即座に終了。

ファイルの内容の内,2行目以降をPowerShellに渡して実行し,cmd.exe自体はそれ以降何もせず終了する。

これにより,2行目以降に記述したPowerShellコードをセキュリティガードを気にせずにそのまま実行できる。

PowerShellのセキュリティガードが存在する限り,この方法が単独ファイルでどのWindowsでもPowerShellを実行する方法となるだろう。

この方法の欠点としては,内容がPowerShellにも関わらず,拡張子が.cmdとなっているため,エディターやIDEのハイライトが適切に表示されないところだろう。

開発中は,拡張子を.ps1にしておき,完成時に,1行目に上記コードを記述し,拡張子を.cmdに変更すればよいだろう。

結論

コマンドプロンプト (cmd.exe) からPowerShellを実行する4の方法を解説した。

実行したいコード行数が数行以内であれば,「1. コマンド引数」の方法で実行し,数行以上である場合,「4. 単独ファイル」の方法で実行すればよいだろう。

cmd.exeで処理するには複雑だが,WSHやC#を使うまでもない場合,これらの方法でPowerShellを使い,問題に対処していきたい。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です