共用方式為


為您的 .NET 項目選擇正確的 PowerShell NuGet 套件

除了與每個 PowerShell 版本一起 pwsh 發佈的可執行套件之外,PowerShell 小組也會維護 NuGet 上可用的數個套件。 這些套件允許以PowerShell作為 .NET中的 API 平台為目標。

作為提供 API 的 .NET 應用程式,且預期載入實作自己的 .NET 連結庫(二進位模組),PowerShell 必須以 NuGet 套件的形式提供。

目前有數個 NuGet 套件提供 PowerShell API 介面區的一些表示法。 選擇與特定專案搭配使用的套件一直缺乏明確指引。 本文闡明了一些常見的情境,以幫助以 PowerShell 為目標的 .NET 專案選擇合適的 NuGet 套件。

託管與參考

有些 .NET 專案會尋求撰寫程式代碼以載入到預先存在的PowerShell運行時間(例如 pwshpowershell.exe、PowerShell 整合式控制台或 ISE),而其他專案則想要在自己的應用程式中執行 PowerShell。

  • 參考 適用於當專案,通常是模組,預定載入至 PowerShell 時。 它必須針對PowerShell提供的 API 進行編譯,才能與其互動,但PowerShell實作是由載入它的PowerShell進程所提供。 若要參考,專案可以使用 參考元件 或實際的執行階段元件作為編譯目標,但必須確保作為其建構的一部分不會發佈其中的任何一項。
  • 主機托管 是指當專案需要自己的 PowerShell 實作時,通常是因為它是一個需要執行 PowerShell 的獨立應用程式。 在此情況下,無法使用純參考元件。 相反地,必須依賴具體的 PowerShell 實作。 由於必須使用具體的 PowerShell 實作,因此必須選擇特定版本的 PowerShell 來作為主機應用程式;一個主機應用程式無法同時支援多個 PowerShell 版本。

發佈以 PowerShell 作為參考的專案

備註

我們會使用本文中的 發佈 一詞來參考執行 dotnet publish,它會將 .NET 連結庫放入具有其所有相依性的目錄中,準備好部署至特定運行時間。

若要防止發佈只用作編譯參考目標的專案相依性,建議設定 PrivateAssets 屬性:

<PackageReference Include="PowerShellStandard.Library" Version="5.1.0.0" PrivateAssets="all" />

如果您忘記這樣做,並使用參考元件作為目標,您可能會看到使用參考元件的預設實作而不是實際實作的相關問題。 這可能採用NullReferenceException的形式,因為參考元件通常會藉由直接傳回null來模擬實作 API。

以 .NET 項目為目標的PowerShell主要類型

雖然任何 .NET 連結庫或應用程式都可以內嵌 PowerShell,但有一些使用 PowerShell API 的常見案例:

  • 實作PowerShell二進位模組

    PowerShell 二進位模組是由 PowerShell 載入的 .NET 連結庫,必須實作 PSCmdletCmdletProvider 類型等 PowerShell API,才能分別公開 Cmdlet 或提供者。 因為模組會載入 ,所以模組會搜尋針對 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 運行時間載入的單一元件。
  • 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 共用的通用介面區。 這可讓單一運行時環境針對產生單一組件,該組件能與多個 PowerShell 版本配合使用,但會產生下列後果:

  • 載入模組或連結庫的 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 4.6.1 NETStandard.Library 實作,以便在舊版 .NET Framework 中提供 netstandard.dll 和其他填充碼元件。

PowerShell 6+ 提供自己的接合元件,將 .NET Framework 4.6.1(及以上版本)的類型轉送至 .NET Core。 這表示只要模組只使用存在於 .NET Core 中的 API,PowerShell 6+ 就可以在針對 .NET Framework 4.6.1 建置時載入並執行它( net461 運行時間目標)。

這表示使用 PowerShell Standard 的二進位模組,可以針對多個 PowerShell 版本,使用單一已發佈的 DLL,有兩個選項:

  1. 發佈針對目標執行環境建置的 net461 組件。 這牽涉到:

    • 發佈適用於 net461 執行環境的專案
    • 同時針對 netstandard2.0 運行時間進行編譯(不使用其組建輸出),以確保所有使用的 API 也都存在於 .NET Core 中。
  2. 發佈目標執行時間的 netstandard2.0 組件建置。 這需要:

    • 發佈適用於 netstandard2.0 執行環境的專案
    • net461取得 NETStandard.Library 的相依性,並將其複製到專案元件的發佈位置,讓元件在 .NET Framework 中經過類型轉送修正。

若要建置以舊版 .NET Framework 為目標的 PowerShell 模組或連結庫,最好以多個 .NET 運行時間為目標。 這會針對每個目標運行時間發佈元件,而且必須在模組載入時間載入正確的元件(例如,以小型 psm1 作為根模組)。

在 .NET 中測試 PowerShell Standard 專案

在 .NET 測試執行器中使用 xUnit 測試模組時,請記住編譯時檢查的作用有限,不能覆蓋所有測試需求。 您必須針對相關的 PowerShell 平台測試您的模組。

若要在 .NET 中測試針對 PowerShell Standard 建置的 API,您應添加 Microsoft.PowerShell.SDK 作為測試相依性(版本需設定為符合所需 PowerShell 版本),並在 .NET Framework 中使用適當的 Windows PowerShell 參考元件。

如需PowerShell Standard的詳細資訊,並用它來撰寫可在多個 PowerShell 版本中運作的二進位模組,請參閱 此部落格文章。 另請參閱 GitHub 上的 PowerShell 標準存放庫

Microsoft.PowerShell.SDK

Microsoft.PowerShell.SDK 是一個中繼套件,將 PowerShell SDK 的所有元件整合成一個單一的 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

Microsoft.PowerShell.SDK以 .NET 應用程式為目標可讓您與所有 PowerShell 的實作元件整合,例如 System.Management.AutomationMicrosoft.PowerShell.Management和其他模組元件。

發佈以 Microsoft.PowerShell.SDK 為目標的應用程式將包含所有這些元件,以及 PowerShell 所需的任何相依項。 它也會包含 PowerShell 在其組建中所需的其他資產,例如 Microsoft.PowerShell.* 模組清單以及 refAdd-Type 所需的目錄。

鑒於 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 的核心。 這個資產主要在 NuGet 上,供 Microsoft.PowerShell.SDK 提取使用。 不過,它也可以直接作為較小的主機方案和版本指定模組的套件。

具體來說,當下列情況時,套件 System.Management.Automation 可能是 PowerShell 功能的最好提供者:

  • 您只想使用 PowerShell 語言功能(例如 System.Management.Automation.Language 命名空間中的 PowerShell 解析器、AST 和 AST 訪問者 API),這些功能可用於 PowerShell 的靜態分析。
  • 您只想要從 Microsoft.PowerShell.Core 模組執行特定命令,而且可以在使用 CreateDefault2 Factory 方法建立的會話狀態中執行它們。

此外, System.Management.Automation 在下列情況下,是有用的參考元件:

  • 您想要以只存在於特定 PowerShell 版本內的 API 為目標
  • 您不會依賴定義在 System.Management.Automation 元件之外的類型(例如,Microsoft.PowerShell.* 模組中 Cmdlet 所導出的類型)。

Windows PowerShell 參考組件

針對 PowerShell 5.1 版和更新版本 (Windows PowerShell),沒有 SDK 可提供 PowerShell 的實作,因為 Windows PowerShell 的實作是 Windows 的一部分。

相反地,Windows PowerShell 參考元件會提供參考目標及重新托管 Windows PowerShell 的方式,功能與 PowerShell SDK 針對第 6 版及以上版本的作用相同。

Windows PowerShell 參考元件會針對每個 Windows PowerShell 版本有不同的套件,而不是依版本區分:

如需如何使用 Windows PowerShell 參考元件的資訊,請參閱 Windows PowerShell SDK

使用這些 NuGet 套件的實際範例

不同的 PowerShell 工具項目會根據其需求,以不同的 PowerShell NuGet 套件為目標。 這裡列出一些值得注意的範例。

PSReadLine 系列

PSReadLine 是 PowerShell 模組,提供許多 PowerShell 豐富的控制台體驗、以 PowerShell Standard 作為相依性而非特定 PowerShell 版本為目標,並以net461 中的 .NET 運行時間為目標

PowerShell 6+ 提供其專用的 shim 元件,允許以運行時間為目標 net461 的 DLL 在載入時「能夠順利運行」(藉由將系結重新導向至 .NET Framework 的 mscorlib.dll 到相關的 .NET Core 元件)。

這可大幅簡化 PSReadLine 的模組配置和傳遞,因為 PowerShell Standard 可確保 PowerShell 5.1 和 PowerShell 6+ 中只會提供所使用的 API,同時允許模組只隨附單一元件。

.NET 4.6.1 目標確實表示不支援在 .NET 4.5.2 和 .NET 4.6 上執行的 Windows PowerShell。

PowerShell 編輯器服務

PowerShell 編輯器服務 (PSES) 是適用於 Visual Studio CodePowerShell 擴充功能的後端,實際上是 PowerShell 模組的形式,由 PowerShell 可執行檔載入,然後接管該程式,在本身內重新裝載 PowerShell,同時提供語言服務通訊協定和偵錯配接器功能。

PSES 提供對應 PowerShell 6+ 的具體實作目標 netcoreapp2.1(因為 PowerShell 7 的 netcoreapp3.1 執行環境是向下相容的),以及針對 Windows PowerShell 5.1 的目標 net461,但其大部分邏輯包含在針對 netstandard2.0 和 PowerShell Standard 的第二個組件中。 這可讓它提取 .NET Core 和 .NET Framework 平臺所需的相依性,同時仍然簡化統一抽象概念背後的大部分程式代碼基底。

由於它是針對 PowerShell Standard 所建置,因此 PSES 需要 PowerShell 的執行時期實作,才能正確進行測試。 若要這樣做, PSES 的 xUnit 測試會提取 Microsoft.PowerShell.SDKMicrosoft.PowerShell.5.ReferenceAssemblies 並在測試環境中提供 PowerShell 實作。

如同 PSReadLine,PSES 無法支援 .NET 4.6 和以下版本,但在呼叫任何可能導致較低 .NET Framework 運行時間損毀的 API 之前,它會在運行時間 執行檢查

PSScriptAnalyzer

PSScriptAnalyzer 是 PowerShell 的 linter,必須專門針對某些版本的 PowerShell 所引進的語法元素。 由於透過實作 AstVisitor2 來辨識這些語法元素,因此無法同時使用 PowerShellStandard 並實作支援較新 PowerShell 語法的 AST 遍歷器方法。

反之,PSScriptAnalyzer 會將每個 PowerShell 版本作為 建置配置,並為每個版本產生個別的 DLL。 這會增加組建大小和複雜度,但允許:

  • 版本特定的 API 定位
  • 要實作的版本特定功能基本上不需要運行時間成本
  • 一路支援 Windows PowerShell 到 .NET Framework 4.5.2

總結

在本文中,我們列出了在實作使用 PowerShell 的 .NET 專案時可選擇使用的 NuGet 套件,並探討選擇各個套件的理由。

如果您已略過摘要,則一些廣泛的建議如下:

  • 如果 PowerShell 模組只需要不同 PowerShell 版本通用的 API,則 PowerShell 模組 應針對 PowerShell Standard 進行編譯。
  • 需要內部執行 PowerShell 的 PowerShell 主機和應用程式 應以 PowerShell 6+ 的 PowerShell SDK 或適用於 Windows PowerShell 的相關 Windows PowerShell 參考元件為目標。
  • 需要 版本特定 API 的 PowerShell 模組應以 PowerShell SDK 或 Windows PowerShell 參考元件作為必要 PowerShell 版本的目標,並將它們當作參考元件使用(也就是,不要發佈 PowerShell 相依性)。