PowerShell チームは、各 PowerShell リリースで発行された pwsh
実行可能パッケージと共に、NuGetで使用できる複数のパッケージも保持しています。 これらのパッケージを使用すると、.NET の API プラットフォームとして PowerShell をターゲットにできます。
API を提供し、独自の (バイナリ モジュール) を実装する .NET ライブラリを読み込む .NET アプリケーションとして、PowerShell を NuGet パッケージの形式で使用することが不可欠です。
現在、PowerShell API のサーフェス領域を何らかの表現で提供する NuGet パッケージがいくつかあります。 特定のプロジェクトで使用するパッケージは、必ずしも明確にされていません。 この記事では、PowerShell を対象とする .NET プロジェクトのいくつかの一般的なシナリオと、PowerShell 指向の .NET プロジェクトを対象とする適切な NuGet パッケージを選択する方法について説明します。
ホスティングと参照
.NET プロジェクトの中には、既存の PowerShell ランタイム (pwsh
、powershell.exe
、PowerShell 統合コンソール、ISE など) に読み込むコードを記述しようとするプロジェクトもあれば、独自のアプリケーションで PowerShell を実行する必要があるプロジェクトもあります。
- の参照は、プロジェクト (通常はモジュール) が PowerShell に読み込まれる場合に使用します。 PowerShell を操作するには、PowerShell が提供する API に対してコンパイルする必要がありますが、PowerShell の実装は PowerShell プロセスによって提供されます。 参照の場合、プロジェクトは 参照アセンブリ または実際のランタイム アセンブリをコンパイル ターゲットとして使用できますが、ビルドでこれらのアセンブリを発行しないようにする必要があります。
- ホスティング は、通常は PowerShell を実行する必要があるスタンドアロン アプリケーションであるため、プロジェクトに独自の PowerShell の実装が必要な場合です。 この場合、純粋参照アセンブリは使用できません。 代わりに、具体的な PowerShell の実装に依存する必要があります。 具体的な PowerShell 実装を使用する必要があるため、ホスティングには特定のバージョンの PowerShell を選択する必要があります。1 つのホスト アプリケーションで PowerShell のバージョンを複数ターゲットにすることはできません。
PowerShell を参照対象とするプロジェクトの発行
手記
この記事 発行 という用語を使用して、実行中の dotnet publish
を参照します。これにより、.NET ライブラリが、そのすべての依存関係を持つディレクトリに配置され、特定のランタイムにデプロイできるようになります。
コンパイル参照ターゲットとして使用されているプロジェクトの依存関係を発行しないようにするには、PrivateAssets 属性を設定することをお勧めします。
<PackageReference Include="PowerShellStandard.Library" Version="5.1.0.0" PrivateAssets="all" />
これを忘れて参照アセンブリをターゲットとして使用すると、実際の実装ではなく、参照アセンブリの既定の実装の使用に関連する問題が発生する可能性があります。 参照アセンブリは多くの場合、NullReferenceException
を返すだけで実装 API をモックするため、これは null
の形式になります。
PowerShell をターゲットとする .NET プロジェクトの主な種類
.NET ライブラリまたはアプリケーションは PowerShell を埋め込むことができますが、PowerShell API を使用するいくつかの一般的なシナリオがあります。
PowerShell バイナリ モジュール の実装
PowerShell バイナリ モジュールは、コマンドレットまたはプロバイダーをそれぞれ公開するために、PSCmdlet や CmdletProvider 型などの PowerShell API を実装する必要がある、PowerShell によって読み込まれる .NET ライブラリです。 これらが読み込まれるため、モジュールによって、そのビルドで公開することなく、PowerShell への参照に対するコンパイルが試みられます。 また、モジュールが複数の PowerShell バージョンとプラットフォームをサポートする必要があるのも一般的であり、ディスク領域、複雑さ、または繰り返し実装のオーバーヘッドを最小限に抑えるのが理想的です。 モジュールの詳細については、about_Modules を参照してください。
PowerShell ホスト の実装
PowerShell ホストは、PowerShell ランタイムの対話レイヤーを提供します。 これは、PSHost が PowerShell の新しいユーザー インターフェイスとして実装される、ホスティングの特定の形式です。 たとえば、PowerShell ConsoleHost は PowerShell 実行可能ファイルのターミナル ユーザー インターフェイスを提供しますが、PowerShell エディター サービス ホストと ISE ホストはどちらも、PowerShell に関するエディター統合の部分的グラフィカル ユーザー インターフェイスを提供します。 ホストを既存の PowerShell プロセスに読み込むことができますが、ホストの実装は、PowerShell エンジンを再配布するスタンドアロンの PowerShell 実装として機能する方がはるかに一般的です。
別の .NET アプリケーションから PowerShell を呼び出す
他のアプリケーションと同様に、PowerShell をサブプロセスとして呼び出してワークロードを実行できます。 ただし、.NET アプリケーションとして、PowerShell をインプロセスで呼び出して、呼び出し元のアプリケーション内で使用するために完全な .NET オブジェクトを取得することもできます。 これは、アプリケーションが内部使用のために独自の PowerShell 実装を保持する、ホスティングのより一般的な形式です。 たとえば、PowerShell を実行してマシンの状態を管理するサービスやデーモン、またはクラウドデプロイの管理などの操作を要求に応じて PowerShell を実行する Web アプリケーションなどです。
.NET からの PowerShell モジュールの単体テスト
PowerShell に機能を公開するように設計されたモジュールやその他のライブラリは、主に PowerShell からテストする必要があります (Pester することをお勧めします)。.NET から PowerShell モジュール用に記述された API を単体テストする必要がある場合があります。 この状況では、モジュール コードが複数の PowerShell バージョンをターゲットにしようとしているのに対し、テストでは特定の具体的な実装で実行する必要があります。
PowerShell NuGet パッケージの概要
この記事では、PowerShell API を公開する次の NuGet パッケージについて説明します。
- PowerShellStandard.Libraryは、複数の PowerShell ランタイムによって読み込むことができる 1 つのアセンブリを構築できる参照アセンブリです。
- Microsoft.PowerShell.SDK 、PowerShell SDK 全体をターゲットにして再ホストする方法
- System.Management.Automation パッケージは、PowerShell ランタイムとエンジンのコア実装であり、最小限のホステッド実装やバージョン固有のターゲット シナリオに役立ちます。
- Windows PowerShell 参照アセンブリ。Windows PowerShell (PowerShell バージョン 5.1 以降) をターゲットにして効果的にリホストする方法です。
手記
PowerShell NuGet パッケージは.NET ライブラリ パッケージではなく、代わりに PowerShell dotnet グローバル ツールの実装を提供します。 これは実行可能ファイルのみを提供するため、どのプロジェクトでも使用しないでください。
PowerShellStandard.Library
PowerShell Standard ライブラリは、PowerShell バージョン 7、6、5.1 の API の共通部分をキャプチャする参照アセンブリです。 これにより、コンパイル時にチェックされた API サーフェスが提供され、.NET コードをコンパイルできます。これにより、.NET プロジェクトは PowerShell バージョン 7、6、および 5.1 をターゲットにすることができ、それが存在しない API を呼び出すリスクはありません。
PowerShell Standard は、PowerShell モジュールまたは PowerShell プロセスに読み込んだ後にのみ実行されるその他のコードを記述するためのものです。 これは参照アセンブリであるため、PowerShell Standard には実装が含まれておらず、スタンドアロンアプリケーションに機能は提供されません。
異なる .NET ランタイムで PowerShell Standard を使用する
PowerShell Standard は、.NET Standard 2.0 ターゲット ランタイムを対象としています。これは、.NET Framework と .NET Core で共有される共通のサーフェス領域を提供するように設計されたファサード ランタイムです。 これにより、1 つのランタイムをターゲットにして、複数の PowerShell バージョンで動作する 1 つのアセンブリを生成できますが、次のような結果になります。
- モジュールまたはライブラリを読み込む PowerShell では、最低でも .NET 4.6.1 が実行されている必要があります。.NET 4.6 および .NET 4.5.2 では .NET Standard はサポートされていません。 新しい Windows PowerShell バージョンは、新しい .NET Framework バージョンを意味しないことに注意してください。Windows PowerShell 5.1 は.NET 4.5.2 で実行できます。
- .NET Framework 4.7.1 以下を実行する PowerShell を使用するには、.NET Framework の古いバージョンにおいて netstandard.dll やその他の shim アセンブリを提供するために、.NET 4.6.1 NETStandard.Library 実装が必要です。
PowerShell 6 以降には、.NET Framework 4.6.1 (以降) から .NET Core への型転送用の独自の shim アセンブリが用意されています。 つまり、モジュールが .NET Core に存在する API のみを使用している限り、PowerShell 6 以降は、.NET Framework 4.6.1 (net461
ランタイム ターゲット) 用にビルドされたときに読み込んで実行できます。
つまり、PowerShell Standard を使用して、1 つの公開 DLL で複数の PowerShell バージョンをターゲットとするバイナリ モジュールには、次の 2 つのオプションがあります。
net461
ターゲット ランタイム用にビルドされたアセンブリを発行する。 これには次の処理が含まれます。-
net461
ランタイム用プロジェクトの発行 - また、(ビルド出力を使用せずに)
netstandard2.0
ランタイムに対してコンパイルして、使用されているすべての API が .NET Core にも存在することを確認します。
-
netstandard2.0
ターゲット ランタイムのアセンブリ ビルドを発行する。 これには次のものが必要です。-
netstandard2.0
ランタイム用プロジェクトの発行 - NETStandard.Library の
net461
依存関係を取得し、それらをプロジェクト アセンブリの発行場所にコピーして、.NET Framework でアセンブリの型転送が修正されるようにします。
-
以前のバージョンの .NET Framework を対象とする PowerShell モジュールまたはライブラリをビルドするには、複数の .NET ランタイムをターゲットにすることをお勧めします。 これにより、ターゲット ランタイムごとにアセンブリが発行され、モジュールの読み込み時に正しいアセンブリを読み込む必要があります (たとえば、ルート モジュールとして小さい psm1 を使用)。
.NET での PowerShell Standard プロジェクトのテスト
xUnit などの .NET テスト ランナーでモジュールをテストする場合は、コンパイル時のチェックはここまでしか実行できない点に注意してください。 関連する PowerShell プラットフォームに対してモジュールをテストする必要があります。
.NET で PowerShell Standard に対してビルドされた API をテストするには、.NET Core とのテスト依存関係として Microsoft.PowerShell.SDK
(目的の PowerShell バージョンに一致するようにバージョンが設定されている) と、.NET Framework で適切な Windows PowerShell 参照アセンブリを追加する必要があります。
PowerShell Standard の詳細と、それを使用して複数の PowerShell バージョンで動作するバイナリ モジュールを記述する方法については、このブログ投稿 を参照してください。 GitHub の PowerShell Standard リポジトリ も参照してください。
Microsoft.PowerShell.SDK
Microsoft.PowerShell.SDK
は、PowerShell SDK のすべてのコンポーネントを 1 つの NuGet パッケージにまとめるメタ パッケージです。 自己完結型の .NET アプリケーションでは、Microsoft.PowerShell.SDK を使用して、外部の PowerShell インストールやライブラリに依存せずに任意の PowerShell 機能を実行できます。
手記
PowerShell SDK は、PowerShell を構成し、PowerShell を使用した .NET 開発に使用できるすべてのコンポーネント パッケージを指します。
特定の Microsoft.PowerShell.SDK
バージョンには、同じバージョンの PowerShell アプリケーションの具体的な実装が含まれています。バージョン 7.0 には PowerShell 7.0 の実装が含まれており、それを使用してコマンドまたはスクリプトを実行すると、主に PowerShell 7.0 での実行と同様に動作します。
SDK から PowerShell コマンドを実行することは、ほとんどの場合、pwsh
から実行するのとまったく同じではありません。 たとえば、start-Job は現在、使用可能な pwsh
実行可能ファイルに依存しているため、既定では Microsoft.PowerShell.SDK
では機能しません。
.NET アプリケーションから Microsoft.PowerShell.SDK
をターゲットにすると、System.Management.Automation
、Microsoft.PowerShell.Management
、その他のモジュール アセンブリなど、PowerShell のすべての実装アセンブリと統合できます。
Microsoft.PowerShell.SDK
を対象とするアプリケーションを発行すると、これらすべてのアセンブリと、PowerShell に必要なすべての依存関係が含まれます。 また、Microsoft.PowerShell.*
モジュールのモジュール マニフェストや、ref
に必要な ディレクトリなど、PowerShell がビルドに必要とするその他の資産も含まれます。
Microsoft.PowerShell.SDK
の完全性を考えると、最適な用途は次の通りです。
- PowerShell ホストの実装。
- PowerShell 参照アセンブリを対象とするライブラリの xUnit テスト。
- .NET アプリケーションからインプロセスで PowerShell を呼び出す。
Microsoft.PowerShell.SDK
は、.NET プロジェクトがモジュールとして使用される場合、または PowerShell によって読み込まれるように意図されているが、特定のバージョンの PowerShell にのみ存在する API に依存する場合にも、参照ターゲットとして使用できます。 特定のバージョンの Microsoft.PowerShell.SDK
に対して発行されたアセンブリは、そのバージョンの PowerShell でのみ安全に読み込んで使用できます。 特定の API を使用して複数の PowerShell バージョンをターゲットにするには、複数のビルドが必要であり、それぞれが独自のバージョンの Microsoft.PowerShell.SDK
を対象とします。
手記
PowerShell SDK は、PowerShell バージョン 6 以降でのみ使用できます。 Windows PowerShell と同等の機能を提供するには、以下で説明する Windows PowerShell 参照アセンブリを使用します。
System.Management.Automation
System.Management.Automation
パッケージは、PowerShell SDK の中核です。 それは主に、Microsoft.PowerShell.SDK
が引き入れるための資産としてNuGetに存在します。 ただし、小規模なホスティング シナリオやバージョンターゲット モジュールのパッケージとして直接使用することもできます。
具体的には、System.Management.Automation
パッケージは、次の場合に PowerShell 機能の推奨プロバイダーになる場合があります。
- PowerShell パーサー、AST、AST ビジター API (PowerShell の静的分析など) などの PowerShell 言語機能 (
System.Management.Automation.Language
名前空間) のみを使用することを検討しています。 -
Microsoft.PowerShell.Core
モジュールから特定のコマンドのみを実行したい場合は、CreateDefault2 ファクトリ メソッドを使用して作成されたセッション状態でそれらを実行することができます。
さらに、System.Management.Automation
は、次の場合に便利な参照アセンブリです。
- 特定の PowerShell バージョン内にのみ存在する API をターゲットにする
-
System.Management.Automation
アセンブリの外部で発生する型 (たとえば、Microsoft.PowerShell.*
モジュールのコマンドレットによってエクスポートされた型) に依存しません。
Windows PowerShell 参照アセンブリ
PowerShell バージョン 5.1 以前 (Windows PowerShell) の場合、Windows PowerShell の実装は Windows の一部であるため、PowerShell の実装を提供する SDK はありません。
代わりに、Windows PowerShell 参照アセンブリは、参照ターゲットと Windows PowerShell を再ホストする方法の両方を提供します。これは、バージョン 6 以降の PowerShell SDK と同じように動作します。
Windows PowerShell 参照アセンブリは、バージョンによって区別されるのではなく、Windows PowerShell のバージョンごとに異なるパッケージを持ちます。
Windows PowerShell リファレンス アセンブリの使用方法については、Windows PowerShell SDK を参照してください。
これらの NuGet パッケージを使用した実際の例
PowerShell ツール プロジェクトが異なると、ニーズに応じて異なる PowerShell NuGet パッケージが対象になります。 いくつかの注目すべき例を次に示します。
PSReadライン
POWERShell の豊富なコンソール エクスペリエンスの多くを提供する PowerShell モジュールである PSReadLine 、特定の PowerShell バージョンではなく依存関係として PowerShell Standard を対象とし、net461
の .NET ランタイムを対象とします。
PowerShell 6 以降では、(.NET Framework の net461
へのバインドを関連する .NET Core アセンブリにリダイレクトすることによって) 読み込まれたときに、mscorlib.dll
ランタイムをターゲットとする DLL が "単に動作する" ことを可能にする独自の shim アセンブリが提供されます。
これにより、PowerShell Standard では PowerShell 5.1 と PowerShell 6 以降の両方に使用される唯一の API が確実に存在し、モジュールは 1 つのアセンブリのみで出荷できるため、PSReadLine のモジュールレイアウトと配信が大幅に簡素化されます。
.NET 4.6.1 ターゲットは、.NET 4.5.2 および .NET 4.6 で実行されている Windows PowerShell がサポートされていないことを意味します。
PowerShell エディター サービス
PowerShell Editor Services (PSES) は、Visual Studio Code用の PowerShell 拡張機能 のバックエンドであり、実際には PowerShell 実行可能ファイルによって読み込まれた後、そのプロセスを引き継いで、言語サービス プロトコルとデバッグ アダプター機能を提供しながら、PowerShell をそれ自体で再ホストする PowerShell モジュールの形式です。
PSES は、(PowerShell 7 の netcoreapp2.1
ランタイムは下位互換性があるため) PowerShell 6 以降をターゲットとする netcoreapp3.1
の具体的な実装ターゲットを提供し、Windows PowerShell 5.1 をターゲットとする net461
しますが、netstandard2.0
と PowerShell Standard を対象とする 2 番目のアセンブリにそのロジックの大部分が含まれています。 これにより、.NET Core および .NET Framework プラットフォームに必要な依存関係を取り込む一方で、統一された抽象化の背後にあるほとんどのコードベースを簡略化できます。
PowerShell Standard に対して構築されているため、PSES では、正しくテストするために PowerShell のランタイム実装が必要です。 これを行うには、テスト環境で PowerShell 実装を提供するために、PSES の xUnit テストで Microsoft.PowerShell.SDK
および Microsoft.PowerShell.5.ReferenceAssemblies
をプルします。
PSReadLine と同様に、PSES は .NET 4.6 以下をサポートできませんが、下位の .NET Framework ランタイムでクラッシュを引き起こす可能性のある API を呼び出す前に、実行時にチェック を実行。
PSScriptAnalyzer
POWERShell のリンターである PSScriptAnalyzer は、特定のバージョンの PowerShell でのみ導入された構文要素をターゲットにする必要があります。 これらの構文要素の認識は、AstVisitor2を実装することによって実現されるため、PowerShellStandard を使用したり、新しい PowerShell 構文に AST ビジター メソッドを実装したりすることはできません。
代わりに、PSScriptAnalyzer は、ビルド構成として 各 PowerShell バージョンを対象とし、それぞれに個別の DLL を生成します。 これにより、ビルド サイズと複雑さが増しますが、次のことができます。
- バージョン固有の API ターゲット設定
- 基本的にランタイム コストなしで実装されるバージョン固有の機能
- .NET Framework 4.5.2 までの Windows PowerShell の完全なサポート
概要
この記事では、PowerShell を使用する .NET プロジェクトを実装するときにターゲットとして使用できる NuGet パッケージと、相互に使用する理由について説明しました。
概要にスキップした場合は、次のような広範な推奨事項があります。
- PowerShell モジュール 異なる PowerShell バージョンに共通の API のみが必要な場合は、PowerShell Standard に対してコンパイルする必要があります。
- PowerShell ホストとアプリケーション PowerShell を内部で実行する必要がある場合は、PowerShell SDK for PowerShell 6 以降、または Windows PowerShell の関連する Windows PowerShell リファレンス アセンブリを対象とする必要があります。
- バージョン固有の API 必要な PowerShell モジュールでは、必要な PowerShell バージョンの PowerShell SDK または Windows PowerShell 参照アセンブリをターゲットにし、それらを参照アセンブリとして使用する必要があります (つまり、PowerShell 依存関係を発行しません)。
PowerShell