ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

winget-cli 配置 PowerShell 模块:Microsoft.WinGet.Configuration Cmdlet 架构与依赖加载机制详解

winget-cli 配置 PowerShell 模块:Microsoft.WinGet.Configuration Cmdlet 架构与依赖加载机制详解 winget-cli 配置 PowerShell 模块Microsoft.WinGet.Configuration Cmdlet 架构与依赖加载机制详解【免费下载链接】winget-cliWinGet is the Windows Package Manager. This project includes a CLI (Command Line Interface), PowerShell modules, and a COM (Component Object Model) API (Application Programming Interface).项目地址: https://gitcode.com/gh_mirrors/wi/winget-cliWindows 包管理器winget-cli的配置Configuration能力可以通过 PowerShell 模块Microsoft.WinGet.Configuration直接驱动。本篇文章基于 winget-cli 仓库中 Microsoft.WinGet.Configuration 模块 README结合该模块 Cmdlets 与 Engine 两个工程的实际源码系统讲解其组成结构、核心 Cmdlet 的语法与使用方式、本地构建流程以及模块为规避程序集依赖冲突而设计的自定义AssemblyLoadContext加载机制。读完本文你将能够安装并调用这套 Cmdlet 完成配置文件的解析、查看与执行并理解在 PowerShell 模块中安全加载 WinRT 依赖的工程实践。模块组成Cmdlets 与 Engine 双层架构Microsoft.WinGet.Configuration模块在源码仓库中由两个独立的 .NET 工程构成职责清晰分离Microsoft.WinGet.Configuration.Cmdlets工程目录包含所有 Cmdlet 的实现是 PowerShell 直接加载的二进制层。Microsoft.WinGet.Configuration.Engine工程目录承载 Cmdlet 背后的真实业务逻辑封装了对 WinGet 配置处理器的调用。这种薄壳 Cmdlet 厚逻辑 Engine的分层设计与仓库中同级的Microsoft.WinGet.Client模块保持一致Client.Cmdlets/Client.Engine便于统一复用底层的配置处理逻辑并降低每个 Cmdlet 类的复杂度。在 模块清单 中可以看到模块的根二进制正是Microsoft.WinGet.Configuration.Cmdlets.dll即模块导入时加载的是 Cmdlets 层。核心 Cmdlet 一览原文档列出模块对外暴露的 5 个核心 Cmdlet。结合 模块清单 与 Cmdlets 目录当前仓库版本实际导出了 10 个 Cmdlet下表将 5 个核心 Cmdlet 与补充 Cmdlet 一并列出Cmdlet别名作用源码文件Get-WinGetConfigurationgwgc打开解析一个配置集支持从文件或历史记录加载GetWinGetConfigurationCmdlet.csGet-WinGetConfigurationDetailsgwgcd获取配置集中各配置单元unit的详细信息GetWinGetConfigurationDetailsCmdlet.csInvoke-WinGetConfigurationiwgc应用配置并同步等待完成InvokeWinGetConfigurationCmdlet.csStart-WinGetConfigurationsawgc启动应用配置不等待完成后台执行StartWinGetConfigurationCmdlet.csComplete-WinGetConfigurationcmpwgc完成先前由Start启动的配置任务并等待结果CompleteWinGetConfigurationCmdlet.csTest-WinGetConfigurationtwgc测试配置集不实际应用TestWinGetConfigurationCmdlet.csConfirm-WinGetConfigurationcnwgc确认配置集可应用性ConfirmWinGetConfigurationCmdlet.csStop-WinGetConfigurationspwgc停止正在运行的配置任务StopWinGetConfigurationCmdlet.csRemove-WinGetConfigurationHistoryrwgch删除配置历史记录RemoveWinGetConfigurationHistoryCmdlet.csConvertTo-WinGetConfigurationYamlctwgcy将配置集转换为 YAML 文本ConvertToWinGetConfigurationYamlCmdlet.cs说明模块清单中Prerelease alpha、ModuleVersion 0.0.1当前为预发布alpha状态实际发布版可通过 PowerShell Gallery 安装见下文示例脚本。Cmdlet 语法与参数详解原文档给出的核心语法如下Get-WinGetConfiguration -File string [CommonParameters] Get-WinGetConfigurationDetails -Set PSConfigurationSet [CommonParameters] Invoke-WinGetConfiguration -Set PSConfigurationSet [-AcceptConfigurationAgreements] [CommonParameters] Start-WinGetConfiguration -Set PSConfigurationSet [-AcceptConfigurationAgreements] [CommonParameters] Complete-WinGetConfiguration -ConfigurationJob PSConfigurationJob [CommonParameters]结合源码可以对参数做进一步说明Get-WinGetConfiguration -File string传入配置文件如.yaml/.yml或.json路径返回一个PSConfigurationSet对象。默认参数集为OpenConfigurationSetFromFile见 GetWinGetConfigurationCmdlet.cs。从源码看它还有另外两个参数集OpenConfigurationSetFromHistory配合-InstanceIdentifier与OpenAllConfigurationSetsFromHistory可用于从配置历史中恢复并支持-ModulePath、-ExecutionPolicy、-ProcessorPath、-CanUseTelemetry等高级参数。Get-WinGetConfigurationDetails -Set PSConfigurationSetSet参数位于 Position 0 且Mandatory true同时支持管道传入ValueFromPipeline/ValueFromPipelineByPropertyName这意味着可直接把上一个 Cmdlet 的输出管道进来。它返回PSGetConfigurationDetailsResult包含每个配置单元的详细状态。Invoke-WinGetConfiguration -Set PSConfigurationSet [-AcceptConfigurationAgreements]同步应用配置直到完成才返回。若不传-AcceptConfigurationAgreements会触发协议确认交互。Start-WinGetConfiguration -Set PSConfigurationSet [-AcceptConfigurationAgreements]异步启动立即返回一个PSConfigurationJob对象适合长任务。Complete-WinGetConfiguration -ConfigurationJob PSConfigurationJob接收Start返回的PSConfigurationJob阻塞等待配置完成并输出结果。从 InvokeWinGetConfigurationCmdlet.cs 可以看到 Cmdlet 的实现骨架BeginProcessing中先调用ConfigurationCommand.ConfirmConfigurationProcessing确认协议ProcessRecord中创建ConfigurationCommand并执行Apply(this.Set)StopProcessing中调用runningCommand.Cancel()支持中断。这些 Cmdlet 大多实现了StopProcessing重写因此在 PowerShell 中按CtrlC可以取消正在执行的配置任务。协议确认Agreements逻辑ConfigurationCommand.cs 中的ConfirmConfigurationProcessing静态方法揭示了协议确认的完整逻辑若用户已传-AcceptConfigurationAgreements直接返回true但仍会调用WriteWarning打印一条警告信息——即使设置了WarningActionPreference.Ignore也保证协议未被接受时用户能看到提示若未传该开关则调用psCmdlet.ShouldContinue弹出确认提示并根据是/否全部yesToAll / noToAll决定结果。该 Cmdlet 的Apply/StartApply路径最终都会走到 Engine 层经由Microsoft.Management.Configuration.Processor调用真实的配置处理器。环境前置条件模块运行的最低 PowerShell 7 版本为7.2.8原文档声明。此外从 模块清单 可见CompatiblePSEditions Core仅兼容 PowerShell Core7.x不支持 Windows PowerShell 5.1PowerShellVersion 7.4.6仓库当前构建目标为 PowerShell 7.4.6底层依赖 Windows 的 WinRT 配置 APIMicrosoft.Management.Configuration.dll按 x86 / x64 架构分别存放因此运行环境为 Windows。遥测Telemetry模块默认启用遥测Telemetry。如要关闭需要设置环境变量$env:POWERSHELL_TELEMETRY_OPTOUT 1 # 或 yes / true该环境变量的取值接受1、yes、true三种形式。这与仓库中其他 PowerShell 模块如Microsoft.WinGet.Client的遥测开关约定一致。本地构建与模块输出位置构建Microsoft.WinGet.Configuration.Cmdlets工程后Microsoft.WinGet.ConfigurationPowerShell 模块会出现在输出目录的PowerShell文件夹下。例如以 x64 Release 配置构建时模块文件位于$(SolutionDirectory)/src/x64/Release/PowerShell也就是说构建后可直接将PowerShell目录加入PSModulePath或用Import-Module指向其中的Microsoft.WinGet.Configuration.psd1进行本地验证。新增 Cmdlet 与依赖加载机制核心工程实践为什么需要自定义 AssemblyLoadContextPowerShell 允许用户在会话中导入多个模块不同模块可能携带同名但不同版本的程序集从而引发程序集依赖冲突assembly dependency conflicts。为了隔离依赖本模块使用了自定义的AssemblyLoadContextALC来加载所有依赖避免与其他应用或模块发生冲突。加载流程与原文档描述一致Microsoft.WinGet.Configuration.Cmdlets.dll是模块导入时加载的入口二进制当Microsoft.WinGet.Configuration.Engine.dll被请求加载时解析处理器resolving handler使用自定义 ALC 加载它之后Engine 的所有依赖都会在该自定义上下文中加载。对应实现见 WinGetAssemblyLoadContext.cs这是一个单例的AssemblyLoadContextisCollectible: falseResolvingHandler先在SharedDependencies中查找应走默认上下文的程序集再在DirectDependencies中查找并交给WinGetAcl.LoadFromAssemblyName加载。而 ModuleInit.cs 实现了IModuleAssemblyInitializer在模块导入时把AssemblyLoadContext.Default.Resolving与ResolvingUnmanagedDll两个事件挂接到上述处理函数模块移除OnRemove时反注册确保不污染全局加载行为。依赖目录布局当前依赖按三个目录组织原文档的Current layoutMicrosoft.WinGet.Configuration.Cmdlets.dll DirectDependencies\Microsoft.WinGet.Configuration.Engine.dll SharedDependencies\Microsoft.Management.Configuration.Processor.dll SharedDependencies\Microsoft.Windows.SDK.NET.dll SharedDependencies\WinRT.Runtime.dll SharedDependencies\x64\Microsoft.Management.Configuration.dll SharedDependencies\x64\Microsoft.Management.Configuration.Projection.dll SharedDependencies\x86\Microsoft.Management.Configuration.dll SharedDependencies\x86\Microsoft.Management.Configuration.Projection.dll目录职责如下DirectDependencies存放解析处理器主动查找并交由自定义 ALC 加载的程序集当前主要是Engine.dllSharedDependencies存放自定义 ALC 能够加载的其余托管依赖SharedDependencies\x64/SharedDependencies\x86按进程架构x64 / x86区分的原生 WinRT 互操作程序集。从 WinGetAssemblyLoadContext.cs 看架构目录名由RuntimeInformation.ProcessArchitecture.ToString().ToLower()计算模块导入时也会校验进程架构必须是 X86 / X64 / Arm64 之一见 ModuleInit.cs。特例WinRT.Runtime.dll原文档特别强调了一个例外WinRT.Runtime.dll不支持在同一进程中被加载多次因为这会影响到 CLR 内部的静态状态。因此它被特殊处理由默认加载器Default Loader加载而不是放入自定义 ALC。在 WinGetAssemblyLoadContext.cs 中可以看到DefaultContextAssemblies常量数组其中包含WinRT.Runtime.dll。ResolvingHandler一旦发现请求的程序集名命中该列表会直接从SharedDependencies中加载到AssemblyLoadContext.Default避免出现 Attempt to update previously set global instance 之类的错误。依赖关系图原文档给出的 mermaid 依赖图揭示了完整的加载关系解读Cmdlets.dll和WinRT.Runtime.dll由默认加载器加载Engine.dll及其余托管依赖由自定义 ALC 加载Engine.dll依赖的其他程序集在 ALC 内解析但Engine.dll中涉及 WinRT 运行时的部分会回落到默认上下文中的WinRT.Runtime.dll。新增 Cmdlet 时的依赖放置规则如果新增 Cmdlet 引入了新的程序集依赖必须将其放入上述布局的正确位置。具体做法是修改Microsoft.WinGet.Configuration.Cmdlets.csproj中的AfterBuild 任务该工程文件位于 Microsoft.WinGet.Configuration.Cmdlets.csproj在构建后将对应 DLL 复制到DirectDependencies、SharedDependencies或按架构区分的子目录中保证运行时解析处理器能找到它。实战完整使用流程仓库在 Examples 目录 提供了两份可直接参考的示例脚本覆盖同步与异步两种用法。同步执行Invoke 模式Sample_InvokeConfiguration.ps1 展示了最小完整流程param ( [Parameter(Mandatory)] $configFile ) if (-not(Get-Module -Name Microsoft.WinGet.Configuration -ListAvailable)) { Install-Module Microsoft.WinGet.Configuration -AllowPrerelease } Import-Module Microsoft.WinGet.Configuration $configSet Get-WinGetConfiguration -File $configFile # 调用该 Cmdlet 不是必须的但若未提前调用 # Invoke/Start 也会在内部执行这一步骤。 $configSet Get-WinGetConfigurationDetails -Set $configSet # 可选加 -AcceptConfigurationAgreements 直接接受协议。 Invoke-WinGetConfiguration -Set $configSet要点通过Install-Module Microsoft.WinGet.Configuration -AllowPrerelease安装预发布版本Get-WinGetConfiguration -File解析配置文件得到$configSetGet-WinGetConfigurationDetails可选用于提前拉取各配置单元的详情Invoke/Start 内部也会执行Invoke-WinGetConfiguration同步应用直到完成才返回。异步执行Start Complete 模式Sample_StartConfiguration.ps1 展示了两阶段异步执行param ( [Parameter(Mandatory)] $configFile ) if (-not(Get-Module -Name Microsoft.WinGet.Configuration -ListAvailable)) { Install-Module Microsoft.WinGet.Configuration -AllowPrerelease } Import-Module Microsoft.WinGet.Configuration # 在后台启动配置 $configJob Get-WinGetConfiguration -File $configFile | Start-WinGetConfiguration # 阻塞直到配置完成若已结束则直接输出结果。 Complete-WinGetConfiguration -ConfigurationJob $configJob要点Start-WinGetConfiguration支持管道输入-Set参数声明了ValueFromPipeline所以可以直接把Get-WinGetConfiguration的结果管道进来返回的$configJob是PSConfigurationJob对象Complete-WinGetConfiguration接收该任务对象并阻塞等待适合需要先做其他工作、稍后再收集结果的场景。与配置处理器Processor的关系从 Engine 层看ConfigurationCommand.cs 定义了两种配置处理器引擎常量dscv3DSC v3默认推荐与pwshPowerShell DSC并维护了 DSC v3 在 Microsoft Store 中的稳定版与预览版包 ID9NVTPZWRC6KQ/9PCX3HX4HZ0Z以及相关组策略WinGet、Configuration、WinGetCommandLineInterfaces的校验。也就是说模块的Apply/Test等操作最终通过Microsoft.Management.Configuration.Processor调度到底层的 DSC v3 资源处理器执行这正是ConfigurationCommand构造函数中传入策略集合的用意见 ConfigurationCommand.cs。小结Microsoft.WinGet.Configuration是 winget-cli 配置能力的 PowerShell 入口采用 Cmdlets薄壳与 Engine核心逻辑双层结构对外提供Get/GetDetails/Invoke/Start/Complete等核心 Cmdlet当前仓库版本还扩展了Test/Confirm/Stop/Remove-WinGetConfigurationHistory/ConvertTo-WinGetConfigurationYaml。其最值得借鉴的工程实践是通过自定义AssemblyLoadContext配合DirectDependencies/SharedDependencies分层目录在 PowerShell 模块中隔离依赖版本冲突并针对WinRT.Runtime.dll做默认上下文加载的特例处理。读者可结合 模块 README、Cmdlets 工程、Engine 工程 与 示例脚本 继续深入。【免费下载链接】winget-cliWinGet is the Windows Package Manager. This project includes a CLI (Command Line Interface), PowerShell modules, and a COM (Component Object Model) API (Application Programming Interface).项目地址: https://gitcode.com/gh_mirrors/wi/winget-cli创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表