鷲ノ巣

C# とか PowerShell とか。当ブログの記事は(特に公開直後は)頻繁に改定される場合があることをご了承ください。

今時のモジュールの書き方

本記事は PowerShell Advent Calendar 2016 の 12 日目の記事です。
昨日は牟田口さんの PowerShellのAST入門です。
明日は jrsyo さんの Windows Update の実行結果(success/fail)をPowerShellでシンプルに取得するです。

…この記事を書いているのは 12/14 の夜中です。
「月曜日に立候補しておけば土日で書けるし余裕余裕」とか思っていましたが週末には一文字も書きませんでした。
弁解のしようもございません。来週こそはちゃんと書きますので許してください。

さて。
「今時のモジュールの書き方」なんて大それたタイトルをぶち上げてみたわけですけれども。
PowerShell Core も発表されたので、マルチ プラットフォームを見据えたモジュールの書き方、ということです。

で、肝心の内容ですが… PSScriptAnalyzer.psm1 でも見て頂ければ、だいたい終わりです。
github.com

うん、さすがにこれじゃあだめですよね。
なので少しだけ蛇足など。

CompatiblePSEditions

PowerShell 5.1 から、モジュール マニフェスト(*.psd1)に CompatiblePSEditions という項目を書けるようになりました。
また、$PSVersionTable にも PSEdition という項目が追加されています。
従来の WindowsPowerShell では 'Desktop'、Windows NanoServer や Linux 版などでは 'Core' という値になります。

うーん、これ、少なくとも現状では機能していないようですね?
Windows 10 上の PowerShell 5.1 の場合、PSEditions は 'Desktop' ですが、CompatiblePSEditions に 'Core' のみを指定したモジュールも読み込めてしまいました。
逆も同様で、PowerShell 6.0 は 'Desktop' なモジュールを読んでしまいました。
まぁ、こちらはまだアルファ版なので、チェックが実装されていないだけかと思ったのですが。5.1 でもスルーされるとは…。

CompatiblePSEditions に関しては、判断材料が足りないのですが、まぁ書かないのが現実的かと思います。
モジュールを PowerShell Gallery に公開するためには、モジュール マニフェストが一定のルールを満たしていなければなりません。
このルールの中に、CompatiblePSEditions を指定した場合、PowerShellVersion が 5.1 以上でなければならないという不可解なものがあるためです。
PowerShellGet 自体は PowerShell 3.0 以上でサポートされていますので、5.0 以下のバージョンでも動かしたい場合は CompatiblePSEditions は書けません
PowerShell Core の最初のバージョンは 5.1*1 ですから、それ未満は暗黙に Desktop であるわけで、Desktop かつ 3.0 とかいう組み合わせが許容されてもいいはずだとは思うのですが、Microsoft は許容してくれません。

不安なのは、CompatiblePSEdition が書かれていない場合は Desktop と Core の両対応とみなされるのかということです。
常識的に考えると、書いていない場合は暗黙的に Desktop を意味するという解釈が普通なのではないかと思うのですが…。

Core 用と Desktop 用の切り替え

PSEdition に応じて異なるバイナリ モジュール(*.dll)を読み込ませるためには、定型ではありますがやや面倒なコードを書かねばなりません。
先述の PSScriptAnalyzer.psm1 もサンプルになりますが、PowerShellGet のドキュメントにも詳細な解説があります。
翻訳して頂いたコミュニティ諸兄に多大な感謝を!

ただ、このあたりはもうちょっとスマートな方法を用意できなかったものかという点は大変不満です。
例えば NuGet パッケージ(*.nupkg)のように、対応する PowerShell のバージョンごとにサブディレクトリを作っておけば、自動的にそれが読み込まれるとか。

というあたりがですね、前回の記事の最後で
f:id:aetos382:20161214021800p:plain
とか言ってたことに相当するわけです。

バイナリ モジュールの作り方

Developing PowerShell Cmdlets for Nano Server | Microsoft Docsというドキュメントがあるにはあるのですが。
これ、読んでみて、どう思われるでしょうか?
個人的には、率直に言いますと「ダサい」ですね。

Microsoft.PowerShell.NanoServer.SDK モジュール自体は ver.1.0.1.0 です。
ver.1.0 以上ということはメジャー リリースなのですね? と言いたくなりますが、同梱されている SDK のバージョンは 0.1 です。
まぁ、.NET Core 向けの開発手順は、project.json をやめて msbuild に回帰するなど、未だ安定しているとは言い難い状況にあります。
VS 2017 での改善が期待される中、現時点でこういった SDK の開発に注力しても無駄になる可能性もあります。

とはいえ、New-NanoCSharpProject コマンドは VS が日本語版だと動かなかったり。
PowerShell Core は NanoServer だけでなく Linux でも Mac でも動くはずであるところ、NanoServer SDK と名乗っているのも妙に気になります。
これは PowerShell Core 用の SDK と考えてもよいものでしょうか?

まぁ、そういった諸々の問題があって、とにかくこいつはダサい。とても v1.0 クオリティとは思えません。

さて一方、nuget.org の方を見てみますと、Microsoft.PowerShell.NanoServer.NetCore.Library という、なんだかそれっぽいパッケージが見つかります。
これは独自に v0.1 とかいう変なランタイムをインストールさせることなく、ちゃんとリリースされた .NET Core を参照しています。
先の NanoServer SDK と比べると、はるかに綺麗な感じがします。

ただ、こっちはドキュメントで言及されていませんし、Install-RemoteDebugger コマンドが付いて来ません。
そのため、果たしてどっちが本命なのか、よくわからない状況になっています。

なお、余談ですが、PowerShell 5 用には Microsoft.PowerShell.5.ReferenceAssemblies というパッケージが公開されています(4.0 や 3.0 用のものもあります)。
PowerShell Desktop 用の開発にはこちらを参照するのが良いでしょう。

一つのプロジェクトでコードを共有しつつ異なるプラットフォーム向けのアセンブリを出力する方法は、以下の記事が参考になります。
blog.bonprosoft.com

PowerShell Core のデバッグ方法に関しては、引き続き調べたいと思います。

おわり

現在 3:40 です。おやすみなさい…

*1:NanoServer 版