からめもぶろぐ。

俺たちは雰囲気で OAuth をやっている

Windows PowerShell と PowerShell Core に対応した PowerShell モジュールを作成する

この記事は PowerShell Advent Calendar 2019 に参加しています。

qiita.com

PowerShell の新しいバージョンである PowerShell Core が提供されて久しいですが、PowerShell モジュールを開発して一般に提供するような場合、互換性を考えて、旧来の Windows PowerShell をサポートしなければならないことがあります。Windows PowerShell は .NET Framework で動作し、PowerShell Core は .NET Core で動作するので、両方に対応したモジュールを作成するにはちょっとした工夫が必要です。

モジュールを PowerShell スクリプトで記述する

PowerShell スクリプト (この場合は .psm1) は実行される PowerShell のバージョンの影響を受けないため、Windows PowerShell と PowerShell Core のどちらでも動作します。ただし PowerShell Core での破壊的変更には注意する必要があります。

docs.microsoft.com

また、PowerShell スクリプトが外部のライブラリ (.dll) に依存する場合、そのライブラリが .NET Standard で作られている必要があります。

マニフェスト ファイルで動的にモジュールを読み込む

モジュールをバイナリ (.dll) で開発する場合、マニフェスト ファイル (.psd1) では RootModule の宣言に対して関数を受けられるようになっており、その中で $PSEdition を判断して読み込むモジュールを変更することができます。.NET Framework と .NET Core の両方でビルドする必要はありますが、安全にモジュールを読み込むことができます。詳細については以下に記載されています。

docs.microsoft.com

モジュールを .NET Standard で作成する

モジュールを .NET Standard (netstandard2.0) でビルドすることで Windows PowerShell と PowerShell Core の両方で動作させることができます。*1 この方法の一番の問題は PowerShell のコア ライブラリである System.Management.Automation.dll の参照になるのですが、以下のように GAC をパス指定で強引に読み込むことで解決します。実行時には必ず System.Management.Automation.dll は読み込まれているので、問題になることはありません。

<ItemGroup>
  <Reference Include="System.Management.Automation">
    <HintPath>C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll</HintPath>
    <Private>false</Private>
  </Reference>
</ItemGroup>

この場合も、依存関係のある外部のライブラリについても .NET Standard 化されていないと厳しいと思います。

(2019/12/25 追記)
コメントいただきました。PowerShellStandard.Library を参照するのが正しい方法とのことです。

まとめ

依存関係もまとめて解決できるので、マニフェスト ファイルで制御するのが最も確実な方法になります。とはいえ、他の方法も悪いというわけではないので、状況に応じて使っていただければよいかと思います。

*1:これは Az モジュールが使っている方法になります。