コマンドレットのパラメータを列挙してみる。2016の1日目です。PowerShellアドベントカレンダー、今年も始まりました。みなさまのご協力の甲斐あって、過去5年間はすべて完走していますが、今回もできれば完走を目指していく感じでまいりましょう。色々な立場の方からの視点でPowerShellを俯瞰できるこのイベント、私自身も毎年楽しんでおります。去年も2015年のPowerShellをまとめる的な記事から始めたわけですが、今年も去年に負けず劣らず、大変革の年だったと思いますので、今回も1年を振り返るところからスタートしましょう。去年のPowerShell5.0登場、周辺モジュールのOSS化といった大きな動きがあってから、今年の前半は少しおとなしめ?の界隈でした(5.0のインストーラーにバグがあって一時非公開とか小騒動はありました)が、まず驚いたのがPowerShellそのものではなくて、Windowsで動くbashが登場したというトピックですね。発表があったのは今年の3月末の事です。Linux"という仕組みの上で動作するUbuntu上で動作するbashとして動作させてしまおうというものです。Windows"という名称になります。このbash、Windowsのシステムを管理するためのものではなく、Web等の開発用途を想定して提供されたものです。本来的にはPowerShellとは関係ないのですが、当初は色々と誤解が飛び交ったように思います。曰く、MSはPowerShellを捨ててやっとbashを採用した。PowerShellとは何だったのか。これらの誤解や疑問には、PowerShellの公式ブログで、bashという新たなシェルがWindowsに追加されたが、両者は並立するものだ、PowerShellはこれからも進化するよ!といった異例の公式見解が示されたりもしました。Updateで正式に利用可能となりました。5.1)のプレビュー版が登場しました。10に同梱されたものの、2016正式版までやや時間を要すこととなりました。5.0にはいくつかの機能や改良が加えられ、結局、5.1というバージョンが登場するに至ったものと思われます。Updateという大型アップデート適用で使えるようになりました。2016にも(もちろん)同梱されました。5.1ではローカルユーザーやグループを扱うコマンドレット等が(ようやく?)追加されたりもしています。Server用のPowerShellが、従来のPowerShellと分離した点でしょう。Edition"と呼ばれます。Edition"が新たに登場しました。Core上で動作します。CoreはOSS(オープンソースソフトウェア)となっています。Serverの管理に必要十分な機能を保っているのではないかと個人的には思っています。今年、PowerShell界をもっとも震撼させたニュース、それは間違いなく、今年8月に実施された、PowerShellのオープンソース化でしょう[GitHub]。Editionを含んだ全体だったので驚きました。Macが登場しました。これも一部の方、特にWindowsやMicrosoft製品を普段あまり使われない方に、割と大きなインパクトを与えていたように思います。system!"になったことの意義についてはちょっと語りつくすには時間が足り無さそうですが、敢えて現実ベースの話を先にすると、一般ユーザー(PowerShellをシステム管理に用いている管理者)にとって、すぐに世界が変化するかというとそうではないんじゃないかという気がしています。いうのも、現在のところOSS版のPowerShellのバージョンは「6.0」とされているものの、まだα版の段階で、基本機能はほぼほぼ5.1と変わらないです。OSS版が改良されても、別に今Windowsで使っているPowerShellがすぐに強くなるわけではありません(現在のところ、サイドバイサイドでインストールする)。オープンソース、マルチプラットフォーム展開を始めたといっても、それは現在の所、PowerShell本体とコアモジュールに留まっていて、コマンド数もたかだか数百個程度でしょう(もうちょっとあるかな?)。PowerShellでOS、サーバー、アプリ、インフラを管理するには、専用のコマンドが山ほど必要になってきますが、それらは今まで通り、Windowsの製品にしか含まれないものです。そのような状況で、たとえばLinuxを管理するのには自分でコマンドを作るか、普通にLinuxのコマンドを呼ぶか...あれそれって別に普通のシェルスクリプトでいいんじゃ...とか。Server上のPowerShellに反映され、両者は一本化される、はず、です、たぶん、が、それはまだアナウンスもなく、いつ、どのような形でもたらされるかは不明と云わざるを得ません。この状況はあくまで現時点の状況です。PowerShellで、WindowsもLinuxもMacも一貫したコマンド&スクリプトで管理できる日が来るかもしれませんね。現在のところは、PowerShellの謎挙動に遭遇したとき、ソースを合法的に眺めて思いを馳せることができるようになったのが大きいかと個人的には思います。腕に覚えのある方は、(ルールに従って)どしどしプルリクエストを投げて、PowerShellを自ら育てていただければな、と思います。1.0が登場してちょうど10年ということで、PowerShell10周年イベントがあったりしました。思えば遠くへ来たものですね。PowerShellを取り巻く状況は刻一刻と変化し、去年と今年ではその傾向が顕著です。2016を、どうぞよろしくお願い致します。2012が始まりました。初日は私が担当させていただきます。3.0の新機能!...ではなく、初心に返って、PowerShellの「関数」ってどう書くのがいいのかというお話をします。1.0から変わっていない基本の話です。これは今までずっと書きたかったネタですがなかなか書く暇がなくて放置してたものです。3.0の話はきっと他の皆さんが書いて下さるはず!私もまた順番が回ってきたら書こうと思います。PowerShellの関数は従来言語とだいぶ違うPowerShellを使いこなすようになってくると、他の言語を使う時と同じで、定型処理は関数として一つにまとめたくなってきます。ところが他の言語と同じような感覚で関数を書くと、どうもうまくいかないのです。引数にフォルダパスとフォルダ名を指定すると、指定フォルダが存在すればFalseを返し、存在しなければ作成してTrueを返す関数を書いてみました。NewFolderと呼び出せばいいんですが(まあ最初はここもつまづきポイントではありますが)、この実行結果は以下のようになります。NewFolderTrueフォルダが作成されてTrueが返却されることを想定していたのに、なんか余計な出力が混じってしまっています。なんでしょうこれは?実はPowerShell関数内で値が出力されると、returnキーワードがついてなくてもすべて呼び出し元に出力されるという仕様なのです。PowerShellにおけるreturnキーワードの効果は「後続処理を打ち切って呼び出し元に戻る。returnの後に値が指定してあればそれを最後の値として戻す」となります。そのため、呼び出し元に返したくない出力が関数内にある場合は、すべて[void]にキャストしたり|Out-Nullとしてリダイレクトするなどして出力を破棄する必要があるのです。ように破棄してやる必要があるわけです。先ほどの例を見ると、「いやいやなんでそんな訳のわからない仕様なんだよ、returnあるときだけ値返せよ」とお思いかと思います。これはPowerShellの特長の一つである、コマンドのパイプラインによる連携を行うための仕様なんです。ここでコマンドを繋ぐパイプラインがどういう動作をしてるか、おさらいします。{$_.Path}これはハンドル数が500以上のプロセスのメインモジュールファイルのパスを取得するというコマンドで、別に何の変哲もありません。稼働中のすべてのプロセスの一覧を配列として取得する。�@で取得した配列を走査して、Handlesプロパティの値を調べる。Handlesが500以上のオブジェクトだけ抽出した配列を生成する。�Aで生成した配列を列挙して、{}内のスクリプトをそれぞれ実行する。稼働中の1つのプロセスオブジェクトを取得して次のコマンドへ送る。そのプロセスのハンドル数が500以上なら、次のコマンドへ送る。そのプロセスに対して{}内のスクリプトを実行する。未取得のプロセスが残っていれば�@に戻る。いう動きをしています。パイプラインの手前で一旦すべての処理を終えてから、出力オブジェクトがまとめて配列という形で次のコマンドに送られるのではなく、オブジェクトがパイプラインの先頭から末尾に向けて1つずつ通過していき、それが先頭コマンドの出力オブジェクト数だけ繰り返される、という動作をしているのです。これがPowerShellのパイプライン処理が、従来の処理系での関数と決定的に違うところで、パイプラインによって複数のコマンドが、あたかももとからあった単一のコマンドのように密に連携するわけです。(この処理、.NETのLINQにちょっと似てると思う方もいらっしゃると思います。LINQとは全然違うものです。類似点も多いのでいずれ比較なんかを書きたいと思ってます)パイプラインで連携可能な関数の書き方さて、先ほどのパイプラインの話ではコマンドレットを連携させていました。PowerShellにおいてはコマンドレットも関数も、それが.NETのクラスかPowerShellのスクリプトなのかの違いがあるだけで、基本は同じ「コマンド」です。関数もコマンドレットと同様、適切な記述をおこなえば、パイプラインでコマンド同士を連携させることが可能です。以下に、Get-Repeatという関数の例を挙げます。この関数は-Textパラメータに文字列を指定し、-Countパラメータに回数を指定すると、指定文字列を指定回数分連結した文字列を出力する、という何の変哲もない関数です。パイプラインからの入力を受け付け、次のパイプラインへ出力することを想定した作りになっています。}}以下は実行例です。2ababcdcdこのように、パラメータに値を指定してもパイプラインから入力しても、スカラー値(配列ではない単一のオブジェクト)でも配列でも、正しく処理されています。この関数をポイントごとに見ていきましょう。PowerShellの正式な関数はparam節、beginブロック、processブロック、endブロックに分かれます。param節にはパラメータを指定します。beginブロックにはパイプラインで連携した際、最初の1回だけ実行される初期化処理、endブロックには最後の1回だけ実行される後始末処理を記述します。beginとendは今回の例では内容を省略しています。processブロックには、パイプラインから入力された1つのオブジェクトに対してその都度実行される処理を記述します。ちなみに、コマンド�@|コマンド�A|コマンド�Bとある場合、各コマンドにおけるbegin,process,endブロックは次のような順番で呼び出されます。コマンド�@begin→コマンド�Abegin→コマンド�Bbegin→{コマンド�@process→コマンド�Aprocess→コマンド�Bprocess→コマンド�@process...}→コマンド�@end→コマンド�Aend→コマンド�Bendprocessブロックでの処理は、通常はパイプラインだけではなくパラメータからも値を入力できるようにしておきます。今回のパラメータには「このパラメータは必須である」を意味するMandatory=$trueもあわせて指定しています。ようにパラメータの型を配列型にしておくことで、どちらを指定しても処理できるようにしています。processブロックではパラメータ経由で配列値が渡された場合に、各要素に対して処理を行うためforeachループを設けています。ちなみにスカラー値が渡された場合もforeachは問題なく処理します。processブロック内では、returnは記述しません。returnするとその時点で関数が終了してしまうので正しくすべての出力ができなくなってしまいます。この例の関数のように入力型と出力型が同一の場合は、processブロックでは1オブジェクトの入力に対して、1オブジェクトを出力するようにしておくと、他のコマンドと連携させやすくなります。Where-Objectコマンドレットのようにフィルタ処理を行う関数の場合は、条件によっては何も出力しないようにします(空の配列とか$nullを返すのではないことに注意)。入力オブジェクトから何らかの配列値を出力する場合もありえます。最低限、これらのポイントを押さえて関数を記述すると、他のコマンドとパイプラインで連携しやすい、PowerShellらしい関数を書くことができると思います。まとめPowerShellでは従来言語と同じ感覚で関数を書くと、うまくいかないことが多いです。処理をひとまとめにしたいというニーズだけならばそれでも問題ないのですが、関数同士を組み合わせたいときに問題が顕在化します。パイプラインの真の動作を理解し、パイプラインの中に組み込んで動作させることを想定した関数を記述すると、他のコマンドレットあるいは自作関数と連携しやすくなり、PowerShellの真の力を解放することができると思います。2012の1日目にしてはえらい固いネタかもですが、基本をおさらいするのも大事ですよね。明日は@jsakamotoさんの番です。2.0の文法、仕様などが詳しく書かれたドキュメント(英文)がMicrosoftから公開されました。2.0http://www.microsoft.com/downloads/en/details.aspx?FamilyID=509b77d0-5e5f-4194-a2d0-61648abfd093320ページのWordファイルです。私はさっそくダウンロードしてpdfで保存しました。(定義済みフィールドプロパティのローカライズの関係上、ヘッダの文字列にエラーが出ているので修正すると良いです。1」にすればOK)PowerShellの文法については公式ドキュメントが長らく公開されていませんでした。1.0のbeta版が公開されたときに付属していたのが公式から出された唯一のものだと思います(RC版からは現行ドキュメントに置き換え)。Promise」が適用されたことと関係があります。Promiseとは、Microsoftが自社開発のプログラミング言語などの特許権を行使しないという宣言で、すでにC#とCLIに適用されているものです。Promiseが適用され、サードパーティがPowerShell言語の実装を自由に行うことができるようになります。Windows以外のプラットフォーム上で動作するPowerShellを合法的に開発することも可能になります。Pashというオープンソースでマルチプラットフォーム対応のPowerShell実行環境のプロジェクトが存在しますが、このプロジェクトの進行を後押しする決定になると思われます。2.0が提供開始になりました。2008の場合では次のような表示になります。MBこの更新プログラムを有効にするには、コンピューターを再起動する必要があります。