読者です 読者をやめる 読者になる 読者になる

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

本記事は 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
とか言ってたことに相当するわけです。

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

Nano Server 用の PowerShell コマンドレットを開発するというドキュメントがあるにはあるのですが。
これ、読んでみて、どう思われるでしょうか?
個人的には、率直に言いますと「ダサい」ですね。

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 版