この記事は、『CRESCO Advent Calendar 2020』15日目の記事です。

 

皆さん、初めまして。システムズエンジニアリングセンターのさつです。
本ブログには初投稿となります。どうぞよろしくお願いいたします。

私は入社2年目のSEとして、プロジェクト内部向けの業務自動化ツールの開発などを主にやってきました。
そのツール開発の中でWindows PowerShellと出会い、その良さを実感しました。

しかし、個人的には、PowerShellはまだまだマイナーな存在、という印象があります。
私のプロジェクトでもそれほど使われている気配がないし、なんとなく「どうしてもPowerShellじゃないとダメな時だけ仕方なく使う」ものという印象があります。

そこで今回は、私の考えるPowerShellの良さを紹介し、PowerShellをもっとメジャーな存在にしたいと思い、本ブログ記事を書くことにしました。

内容としては私のPowerShellに対する感想を中心に述べ、機能や文法の詳細な解説は行いません、というか行うだけの力がまだありません。
「やりたいこと powershell」などでWEB検索すれば、情報はたくさん出てきます(私もそうやって調べました)。

なお、ここで対象とするPowerShellのバージョンは、1607以降のWindows 10に標準搭載されている、Windows PowerShell 5.1とします。
クロスプラットフォームになった、より新しいバージョンがとっくの昔に出ていますが、そちらについては私はよく知りませんのであしからず。

PowerShellとは?

まず初めに、PowerShellの概要についてごく簡単に説明しておきます。

PowerShellとは、MicrosoftがWindows用に開発した新たなコマンドライン環境・スクリプト言語のことです(前述の通り、現在はクロスプラットフォームになっています)。

Windowsでコマンドラインといえば、従来からコマンドプロンプト(cmd.exe)がありますが、PowerShellは「新しいコマンドプロンプト」と考えることができます。

従来のコマンドプロンプトと比較した場合のPowerShellの最大の特徴は、「オブジェクト指向である」ことと、「.NET Frameworkを基盤としている」ということであり、それがそのままPowerShellの良さにつながっていきます。

PowerShellの良いところ

オブジェクト指向

PowerShellでもコマンドプロンプトでも、コマンドを入力すれば画面に結果が出力されます。
しかし、コマンドプロンプトではコマンドの出力結果は「文字列」で表されるのに対し、PowerShellでは「.NETのオブジェクト」としてあらわされます。

これの何が良いのかというと、「コマンドの出力結果が最初から構造化されている」ということ、つまり出力結果を自分でパースする必要がほとんどなくなるということです。

例えば、PC上で動いているプロセスの一覧を取得するには、PowerShellでは「get-process」というコマンドを使います。
このコマンドは、「System.Diagnostics.Process」クラスのインスタンスの配列を出力します。

「System.Diagnostics.Process」というのは、C#などを使用したことのある方ならご存じの方も多いと思いますが、プロセスを表す.NETのオブジェクトです。
オブジェクトであるということは、プロパティを参照したりメソッドを呼び出したりすることができるわけです。

たとえば、プロセス名は「ProcessName」プロパティを、PIDは「ID」プロパティを参照すれば確認できます。また、プロセス一覧の総数を取得するのも、配列の「Length」プロパティにアクセスするだけです。

このように、コマンドの出力結果がオブジェクトであれば、文字列の中から自分が必要とする情報を取り出すにはどうするかということを考える労力を削減することができます。
もちろん、オブジェクトのプロパティやメソッドについて知っておく必要はありますが、WEBに豊富に情報があるので、困ることはあまりないと思います。

また、PowerShellには、大量のオブジェクトの中から特定のプロパティの値でフィルタやソートを行うコマンドが充実しており、これまでの文字列主体のシェルよりも簡単にデータの加工ができます。

.NET Frameworkの知識がそのまま役に立つ

PowerShellは、.NETを基盤とするシェルです。

数値でも文字列でも、配列でもコマンドが出力するその他のオブジェクトであっても、それらはすべて.NETのオブジェクトです。
C#やVB.NETなどの.NET上で動作するプログラミング言語を扱ったことがあれば、そこで得た知識がPowerShellでも基本的にそのまま通用します。

一方、.NETでの開発経験がない場合でも、例えばC#やVB.NET向けに書かれたWEBの記事などが(多少の読み替えは必要ですが)役に立つことは多いと思います。
また、PowerShellには、.NET用のアセンブリ(DLLファイル)を読み込んで使用することもできるようになっています。

このため、.NET向けのライブラリ資産の多くを流用でき、単なる高機能なコマンドプロンプトにとどまらず、様々な処理にPowerShellを応用できます。
一例として、(コード量は多くなりますが)Windows Formsを使用したGUIの作成もやろうと思えばできます。

様々なデータフォーマットを簡便に処理できる

PowerShellには、CSVやJSON形式のデータを読み書きするためのコマンドが標準で用意されています。
また、どちらかというと.NET自体の機能ですが、XMLのパースも行えます。

CSVに関しては、単純なコンマ区切りならまだしも、ダブルクォートが使用されている場合などを考慮しようとすると面倒になってくるので、コマンド1発で読み書きができるのはありがたいと感じました。

また、JSONやXMLを扱えるということは、例えばHTTP通信などと組み合わせて、WEBサービスのRest APIを操作するなどの処理が実現できます。

標準では容易に扱えないデータフォーマットがあったとしても、上述のように.NETのライブラリが流用できるので、そのあたりは柔軟に対応できるのではと思います。

PowerShellの欠点

ここまでさんざん礼賛してきたPowerShellにも、もちろん欠点はあります。
PowerShellを常用するなら、欠点ともうまく付き合っていかなければなりません。

PowerShellの欠点の中で、私が特に気になったものを3つ紹介します。

文法上・仕様上の「落とし穴」が多い

PowerShellは、コマンドシェルとしてもスクリプト言語としても利用されます。
また、従来のコマンドプロンプトや他のコマンドシェルなどから乗り換える人もいます。

PowerShellには、こうしたことに配慮したのであろうという仕様がところどころに見られますが、それがかえって直観に反する動作結果をもたらし、私も困惑したことが多くありました。

たとえば、「1+1」と入力して実行すると結果は「2」となるのに、「echo 1+1」を実行すると式が評価されずに、「1+1」がそのまま出力されます。

このような仕様は、「コードを書く、エラーに遭遇する、原因を調べる」のサイクルを何度も回しながら地道に覚えていくしかありません。
しかし、これはほかのプログラミング言語でも多かれ少なかれ同じことですし、1度エラーや不可解な動作に遭遇して覚えた仕様はそう簡単には忘れないものです。

実行ポリシーについて

PowerShellには、意図しないスクリプトを誤って実行するのを防ぐために「実行ポリシー」という仕組みが備わっています。

しかし、そのせいで、初期状態ではスクリプトファイルを作成してもダブルクリックでは実行できないようになっています。
そのため、PowerShellでスクリプトを作成してそれを利用者に配布して利用させるという場合に少々手間がかかります。

最も安全で確実な方法は、起動用のバッチファイル(.batファイル)を作成することです。

PowerShellは、コマンドライン引数で実行ポリシーを変更できるようになっているので、起動用のバッチファイルから「powershell.exe -ExecutionPolicy RemoteSigned スクリプトファイル名」のようにして起動すると、スクリプトファイルが実行されるようになります。

ただ、この方法も、ファイルが2つに分かれてしまうということと、「バッチファイルのほうを起動してね」と利用者に説明する必要が生じるので、面倒くささは残ってしまいます。
(一応、ユーザーレベルやシステムレベルで実行ポリシーを緩くすればダブルクリックで実行できるようにはなりますが、おすすめはしません)

COMオブジェクトは解放処理が面倒

.NET Frameworkには、COMオブジェクトをシームレスに呼び出すことができる仕組みとして、ランタイム呼び出し可能ラッパー(RCW)と呼ばれる仕組みがあり、PowerShellでもそれが利用できます。
COMオブジェクトが扱えれば、IEやExcelを自動操作できるなど何かと便利ですが、PowerShellでは、というか.NETでは、いらなくなったオブジェクトの解放処理が何かと面倒です。

生成されるCOMオブジェクトが1つや2つなら良いですが、Excel操作時などCOMオブジェクトが大量に生成される場合、それらをすべて開放する必要があります。
解放を忘れると、例えばExcelのプロセスがいつまでも残ってしまったりするみたいです。

本当は、「PowerShellではCOMオブジェクトも自在に扱えます」と本記事に書こうと思っていたのですが、この事実を知って書くのをやめました。w
上述の通り、PowerShellでは.NETの資産が使えますので、COMオブジェクトが使えなくても他の選択肢もそんなに少なくはないと思いますし、何でもPowerShellでやらなければいけないわけでもないのですから、COMを使う場面ではWSH(VBSなど)を使用するというのも手です。

終わりに

今回は、PowerShellについて語ってみましたが、いかがだったでしょうか。
私の感想が中心でつまらなかったかもしれませんが、本記事をきっかけに、PowerShellに興味を持ち、常用する人が1人でも多くなれば幸いです。

初投稿で拙い記事になってしまいましたが、より良い記事を書けるようになっていきたいと思いますので、今後ともよろしくお願いいたします。
最後までお読みいただき、ありがとうございました。