PowerShellに挑んでみる

PowerShellは、マイクロソフトが2006年ごろ発表したコマンドラインシェルおよびスクリプト言語だ。
Linuxなどでいうbashのようなもので、古臭いコマンドプロンプトを捨てて洗練された形に作り直したものだ。
このPoserShell、世間で一般的に使われるようになったという話をさっぱり聞かない。
むしろWindows 10でUbuntuコマンドライン環境が使えるようになったりして、あれ?PowerShellはいらないコなのかな?という気さえする。

だが待ってほしい、Windows 10にbashが導入されたころ、PowerShellが他OSに提供されるという発表があった。
MicrosoftがPowerShellをオープンソース化しLinuxやOS Xにも提供…Bash on Windowsとの差別化は?
bashは取り入れる、しかしPowerShellも同格のものとして認めさせる、マイクロソフトPowerShellへの自信が現れているようだ。

私の個人的な印象として、PowerShellLinuxなどでシェルとして広く使われることはないと思う。
同様に、Windows 10において、コマンドラインが完全にbashに替わられることもないと思う。
Windowsの自動操作はPowerShellで行い、Linuxマイクロソフトのプロダクトを使用する際のスクリプトPowerShellは使われていくのだろう。
そういったシェルの1種として、PowerShellの特徴を知っておくことは意味があると、私は10年目にして思った。

さてさて、基本的な文法などはネットを検索すれば腐るほど出てくるので、この記事では、10年間私がPowerShellを勉強しようと思いながら結局よくわかっていないこと、を中心に書いていこうと思う。
10年間かけていまだにピンと来ない、ということは、もしかすると真に革新的なことを私が見落としている可能性があるのだ。

1.PowerShellコマンドラインプログラムなのか?
Windowsでプログラミングをしたことがあれば、コマンドライン(コンソール)とウィンドウの大きく2種類のプログラムを作成できることを知っているだろう。
PowerShellのアイコンをスタートメニューからクリックすると、青色のウィンドウに文字だけの、いかにもコマンドラインな画面が表示される。
しかしこれは、コマンドプロンプト上でPowerShellが動いているわけではない。
タスクマネージャで見ても「Windows コマンドプロセッサ」ではなく、「Windows PowerShell」として表示されている。
じゃあ、PowerShell .NET で作られたウィンドウプログラムなのかな?
PowerShellの実体は以下にある。

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe  ※x64版
C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe  ※x86

さて、コマンドプロンプトを起動しよう。そして、上記のexeのパスを入力してEnterを押してみよう。
どうだろう。普通にコマンドプロンプトの中でPowerShellが起動したのではないだろうか。
つまり、PowerShellは「完全にコマンドラインプログラムだ」ってことだ。

蛇足だが、Windowsのプロセスについて。
Windows 10のタスクマネージャではプロセスが「アプリ」「バックグラウンド プロセス」「Windows プロセス」に分かれている。
コマンドプロンプトPowerShellを起動すると、「アプリ」に1件増えるのと同時に、「Windows プロセス」にもConsole Window Host(conhost.exe)が1件増える。コマンドラインプログラムは本来ウィンドウを持たないため、かわりにconhost.exeがウィンドウを提供し、内部でコマンドラインプログラムを動かすのだ。普段私たちが触っているコマンドプロンプトは、つまりconhost.exeのことなのである。
コマンドプロンプトPowerShellの中でさらにコマンドプロンプトPowerShellを起動すると、「バックグラウンド プロセス」に1件増える。exitすると1件減る。コマンドプロンプトPowerShellで、プログラム的な立ち位置は何も変わっていないのだ。

2.コマンドレット(cmdlet)とは何ぞや?
コマンドプロンプトでは、exeファイル名を指定して実行するほかに、cd とか dir とかの「コマンド」が使えた。これらはcmd.exeの内部に含まれている機能だ。
PowerShellでも同様のことはできる。これをコマンドレットと呼ぶ。

旧コマンド → PowerShellコマンドレット
dir  → Get-ChildItem
cd   → Set-Location
copy → Copy-Item

こことか見るといいんじゃないかな。
PowerShell/PowerShell、コマンドプロンプト、Linuxコマンド対応表
全般的にPowerShellコマンドレットはクソ長たらしいので、こんなものをクソまじめに手打ちしていたらクソ腱鞘炎になってしまうので、別名(alias)が用意されており昔のコマンド名でつかえるようになっている。

これらのコマンドレットはpowershell.exeの中に内蔵されているのだろうか?
否である。

PS C:\Users\hogehoge> Get-Command | Where-Object { $_.Name -eq "Set-Location" }

CommandType     Name                                               Version    Source
 ----------     ----                                               -------    ------
Cmdlet          Set-Location                                       3.1.0.0    Microsoft.PowerShell.Management

上記のように、例えば Set-Location は、Microsoft.PowerShell.Managementというモジュールに含まれている。
モジュールは、powershell.exeのある所の下にModulesフォルダがあって、その中に同名のフォルダがある。
上記の例だと、Microsoft.PowerShell.Management.psd1というテキストファイルが1個あるだけだが、中身をのぞくと実体は Microsoft.PowerShell.Commands.Management.dll の中にあるらしい。
検索するとC:\Windows\WinSxSの下に同名のdllがあって、という具合に、PowerShellの機能は外部のモジュールで拡張できるようになっている。

なお、PowerShellが扱えるモジュールは大きく以下の4種がある。


まあ、ここら辺まで来ると、正直bashなんて敵じゃないな、と思う。
使い勝手は別にして、プログラミング言語の機能で見たときに、以下ぐらいの実力はあると思うんだ。

バッチファイル < bash < Perl ≦ PowerShell < RubyPython


他にも、コマンドレットの入出力をテキストではなくオブジェクトで受け渡しできたりとか、おもしろい機能があると思う。
しかし口当たりが非常にまずい。こんなクソ長い名前を覚えたくないし打ちたくもない。
楽しくスクリプトを書けるような甘ーいラッパーを誰かが作った時に、PowerShellはブレイクしたりするかもしれなくもなきにしもあらず。