当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 为您的 .NET 项目选择正确的 PowerShell NuGet 包

作者:精品下载站 日期:2024-12-14 02:56:47 浏览:13 分类:玩电脑

为您的 .NET 项目选择正确的 PowerShell NuGet 包


除了随每个 PowerShell 版本发布的 pwsh 可执行包之外,PowerShell 团队还维护了 NuGet 上的多个可用包。这些包允许将 PowerShell 定位为 .NET 中的 API 平台。

作为提供 API 并期望加载实现其自身(二进制模块)的 .NET 库的 .NET 应用程序,PowerShell 以 NuGet 包的形式提供至关重要。

目前有几个 NuGet 包提供了 PowerShell API 表面区域的一些表示。对于特定项目使用哪个包并不总是很明确。本文介绍了面向 PowerShell 的 .NET 项目的一些常见场景,以及如何为面向 PowerShell 的 .NET 项目选择正确的 NuGet 包。

托管与引用

一些 .NET 项目寻求编写要加载到预先存在的 PowerShell 运行时的代码(例如 pwshpowershell.exe、PowerShell 集成控制台或 ISE),而其他人则希望在自己的应用程序中运行 PowerShell。

  • 引用适用于将项目(通常是模块)加载到 PowerShell 中的情况。它必须针对 PowerShell 提供的 API 进行编译才能与其交互,但 PowerShell 实现是由加载它的 PowerShell 进程提供的。为了引用,项目可以使用引用程序集或实际运行时程序集作为编译目标,但必须确保它不会在其构建中发布任何这些内容。
  • 托管是指项目需要自己的 PowerShell 实现,通常是因为它是需要运行 PowerShell 的独立应用程序。在这种情况下,不能使用纯参考程序集。相反,必须依赖具体的 PowerShell 实现。由于必须使用具体的PowerShell实现,因此必须选择特定版本的PowerShell进行托管;单个主机应用程序无法实现多目标 PowerShell 版本。

发布以 PowerShell 为参考的项目

笔记

我们在本文中使用术语 发布 来指代运行 dotnet 发布,它将 .NET 库及其所有依赖项放入一个目录中,准备部署到特定的目录运行时。

为了防止发布仅用作编译参考目标的项目依赖项,建议设置 PrivateAssets 属性:

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

如果您忘记执行此操作并使用参考程序集作为目标,则可能会遇到与使用参考程序集的默认实现而不是实际实现相关的问题。这可能采用 NullReferenceException 的形式,因为引用程序集通常通过简单地返回 null 来模拟实现 API。

针对 PowerShell 的 .NET 项目的主要类型

虽然任何 .NET 库或应用程序都可以嵌入 PowerShell,但有一些使用 PowerShell API 的常见场景:

  • 实现 PowerShell 二进制模块

    PowerShell 二进制模块是由 PowerShell 加载的 .NET 库,必须实现 PowerShell API(例如 PSCmdlet 或 CmdletProvider 类型)才能分别公开 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 标准库是一个参考程序集,它捕获了 PowerShell 版本 7、6 和 5.1 的 API 的交集。这提供了一个编译时检查的 API 接口来编译 .NET 代码,从而允许 .NET 项目以 PowerShell 版本 7、6 和 5.1 为目标,而不必冒调用不存在的 API 的风险。

PowerShell Standard 旨在编写 PowerShell 模块或仅在将其加载到 PowerShell 进程后运行的其他代码。由于它是一个参考程序集,PowerShell Standard 本身不包含任何实现,因此不为独立应用程序提供任何功能。

将 PowerShell Standard 与不同的 .NET 运行时结合使用

PowerShell Standard 针对 .NET Standard 2.0 目标运行时,这是一个外观运行时,旨在提供 .NET Framework 和 .NET Core 共享的公共表面区域。这允许以单个运行时为目标来生成可与多个 PowerShell 版本一起使用的单个程序集,但会产生以下后果:

  • 加载模块或库的 PowerShell 必须至少运行 .NET 4.6.1; .NET 4.6 和 .NET 4.5.2 不支持 .NET 标准。请注意,较新的 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 来通过单个已发布 DLL 定位多个 PowerShell 版本的二进制模块有两个选项:

  1. 发布为 net461 目标运行时构建的程序集。这涉及:

    • net461 运行时发布项目
  2. 还针对 netstandard2.0 运行时进行编译(不使用其构建输出),以确保使用的所有 API 也存在于 .NET Core 中。
  3. 发布 netstandard2.0 目标运行时的程序集构建。这需要:

    • netstandard2.0 运行时发布项目
  4. 获取 NETStandard.Library 的 net461 依赖项并将它们复制到项目程序集的发布位置,以便在 .NET Framework 中对程序集进行类型转发更正。

要构建针对旧版 .NET Framework 版本的 PowerShell 模块或库,最好针对多个 .NET 运行时。这将为每个目标运行时发布一个程序集,并且需要在模块加载时加载正确的程序集(例如使用小型 psm1 作为根模块)。

在 .NET 中测试 PowerShell 标准项目

当涉及到在 xUnit 等 .NET 测试运行程序中测试模块时,请记住编译时检查只能进行到此为止。您必须针对相关 PowerShell 平台测试您的模块。

要测试针对 .NET 中的 PowerShell Standard 构建的 API,您应该添加 Microsoft.Powershell.SDK 作为 .NET Core 的测试依赖项(版本设置为与所需的 PowerShell 版本匹配),并添加适当的Windows PowerShell 参考带有 .NET Framework 的程序集。

有关 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 一起使用。

通过从 .NET 应用程序定位 Microsoft.Powershell.SDK,您可以与所有 PowerShell 的实现程序集集成,例如 System.Management.AutomationMicrosoft.PowerShell .管理,以及其他模块组件。

发布面向 Microsoft.Powershell.SDK 的应用程序将包含所有这些程序集以及 PowerShell 所需的任何依赖项。它还将包括 PowerShell 在其构建中所需的其他资产,例如 Microsoft.PowerShell.* 模块的模块清单和 Add-Type 所需的 ref 目录。

鉴于 Microsoft.Powershell.SDK 的完整性,它最适合:

  • PowerShell 主机的实现。
  • 针对 PowerShell 参考程序集的库的 xUnit 测试。
  • 从 .NET 应用程序进程内调用 PowerShell。

当 .NET 项目打算用作模块或由 PowerShell 加载时,Microsoft.PowerShell.SDK 也可以用作参考目标,但依赖于仅存在于特定版本的 API PowerShell。请注意,针对特定版本的 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 工厂方法创建的会话状态中执行它们。

此外,在以下情况下,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 提供不同的包:

  • 电源外壳 5.1
  • 电源外壳4
  • 电源外壳3

有关如何使用 Windows PowerShell 参考程序集的信息可以在 Windows PowerShell SDK 中找到。

使用这些 NuGet 包的真实示例

不同的 PowerShell 工具项目根据其需求针对不同的 PowerShell NuGet 包。这里列出了一些值得注意的例子。

PS阅读线

PSReadLine 是提供 PowerShell 丰富控制台体验的 PowerShell 模块,它以 PowerShell Standard 作为依赖项而不是特定的 PowerShell 版本,并以 csproj 中的 net461 .NET 运行时为目标。

PowerShell 6+ 提供自己的填充程序集,允许面向 net461 运行时的 DLL 在加载时“正常工作”(通过将绑定重定向到 .NET Framework 的 mscorlib.dll 到相关的 .NET Core 程序集)。

这显着简化了 PSReadLine 的模块布局和交付,因为 PowerShell Standard 确保所使用的唯一 API 将同时出现在 PowerShell 5.1 和 PowerShell 6+ 中,同时还允许模块仅随单个程序集一起提供。

.NET 4.6.1 目标确实意味着不支持在 .NET 4.5.2 和 .NET 4.6 上运行的 Windows PowerShell。

PowerShell 编辑器服务

PowerShell 编辑器服务 (PSES) 是 Visual Studio Code 的 PowerShell 扩展的后端,实际上是 PowerShell 模块的一种形式,由 PowerShell 可执行文件加载,然后接管该进程以在自身内部重新托管 PowerShell,同时还提供语言服务协议和调试适配器功能。

PSES 为 netcoreapp2.1 提供具体的实现目标,以面向 PowerShell 6+(因为 PowerShell 7 的 netcoreapp3.1 运行时向后兼容),并为 net461 提供具体的实现目标面向 Windows PowerShell 5.1,但在面向 netstandard2.0 和 PowerShell Standard 的第二个程序集中包含其大部分逻辑。这使得它能够引入 .NET Core 和 .NET Framework 平台所需的依赖项,同时仍然简化统一抽象背后的大部分代码库。

由于 PSES 是根据 PowerShell 标准构建的,因此需要 PowerShell 的运行时实现才能正确进行测试。为此,PSES 的 xUnit 测试引入了 Microsoft.PowerShell.SDK 和 Microsoft.PowerShell.5.ReferenceAssemblies,以便在测试环境中提供 PowerShell 实现。

与 PSReadLine 一样,PSES 无法支持 .NET 4.6 及更低版本,但它会在调用任何可能导致较低 .NET Framework 运行时崩溃的 API 之前在运行时执行检查。

PS脚本分析器

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 Standard 进行编译。
  • 需要在内部运行 PowerShell 的 PowerShell 主机和应用程序应以适用于 PowerShell 6+ 的 PowerShell SDK 或适用于 Windows PowerShell 的相关 Windows PowerShell 参考程序集为目标。
  • 需要特定于版本的 API 的 PowerShell 模块应针对所需 PowerShell 版本的 PowerShell SDK 或 Windows PowerShell 参考程序集,将它们用作参考程序集(即不发布 PowerShell 依赖项)。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯