CMDからPowerShellを実行する4の方法

GNOME Terminal

導入

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

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

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

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

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

PowerShellのコマンドラインオプションについては公式サイトの「about_PowerShell_exe – PowerShell | Microsoft Docs」を参考にした。

1.コマンド引数

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

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

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

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

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

なお,-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 - <file.ps1
powershell -ExecutionPolicy Unrestricted .\file.ps1 del file.ps1

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

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

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

オプション指定が面倒なので,4行目のように標準入力経由で受け取ったほうが簡単だ。

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

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

4. 単独ファイル

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

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

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

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

単独ファイルでの実行方法の手順
  1. -ExecutionPolicy Unrestricted: セキュリティガードを回避。
  2. Get-Content "%~f0": 絶対パスで0番目の引数である自分自身のファイルの内容を出力。
  3. ^| Select-Object -Skip 1: ファイルの内容をパイプで受け取り,1行目をスキップして出力。
  4. | @powershell %* -: ファイルの内容をpowershellで実行。
  5. & exit /b: PowerShellの実行結果を引き継いでCMDは即座に終了。

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

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

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

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

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

なお,当初はInvoke-Expressionを用いていた。

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

後 (2022-01-02) で見直して,冗長に感じたのでpowershellで文字列を受け取るように修正した。

結論

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

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

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

CMDからPowerShellを実行する4の方法” に対して2件のコメントがあります。

コメントを残す

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