适用于 PowerShell 5.1 及以上版本
PowerShell 模块生态在过去几年里蓬勃发展,PowerShell Gallery 上已经托管了数以万计的模块。从日常运维的 Active Directory 管理,到云端自动化的 Az 模块,再到新兴的 AI 交互工具,几乎每种场景都有对应的模块可用。然而,模块数量的增长也带来了管理上的挑战:不同项目依赖同一个模块的不同版本、私有环境的离线分发需求、以及供应链安全对模块来源的审计要求,都是实际工作中必须面对的问题。
PowerShell 7 引入了 PSResourceGet (Microsoft.PowerShell.PSResourceGet)作为新一代包管理引擎,替代了沿用多年的 PowerShellGet v2。PSResourceGet 基于 NuGet 协议重新实现了仓库交互,在性能、安全性和功能覆盖面上都有显著提升。同时,它保留了与 PowerShellGet 类似的命令风格,降低了迁移成本。对于仍然运行在 Windows PowerShell 5.1 环境中的系统,PowerShellGet 依然可用,但强烈建议尽早迁移到 PSResourceGet。
本文将从基础操作入手,逐步介绍模块搜索与安装、版本锁定与依赖分析,以及私有仓库的搭建方法,帮助你在不同规模的自动化环境中实现可靠的包管理与依赖控制。
PSResourceGet 基础操作 PSResourceGet 的核心操作围绕”仓库(Repository)”展开。仓库是模块的存储和分发端点,默认连接到 PowerShell Gallery。下面的代码展示了从注册仓库到搜索、安装、更新模块的完整流程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Install-Module Microsoft.PowerShell.PSResourceGet -Force -Scope CurrentUserGet-PSResourceRepository Register-PSResourceRepository -Name 'MyCompanyFeed' -Uri 'https://nuget.mycompany.com/v3/index.json' Find-PSResource -Name '*Az*' -Type Module -Repository 'PSGallery' | Select-Object Name, Version, Description | Format-Table -AutoSize Install-PSResource -Name 'Pester' -Scope CurrentUser -TrustRepository Install-PSResource -Name 'Pester' -Version '5.5.0' -Scope CurrentUserUpdate-PSResource -Name 'Pester' -Scope CurrentUserGet-InstalledPSResource -Name 'Pester'
上述代码中,Register-PSResourceRepository 用于注册自定义仓库,Find-PSResource 支持通配符搜索并可以限定仓库范围,Install-PSResource 和 Update-PSResource 分别完成安装与升级操作。-TrustRepository 参数表示信任该仓库,避免每次安装时都弹出确认提示。
执行结果示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Name Uri Trusted PSGallery https://www.powershellgallery.com/api/… False MyCompanyFeed https://nuget.mycompany.com/v3/index … True Name Version DescriptionAz 12.0 .0 Microsoft Azure PowerShell Az.Accounts 3.0 .0 Microsoft Azure PowerShell - Accounts Az.Compute 7.0 .0 Microsoft Azure PowerShell - Compute Name Version Prerelease Repository DescriptionPester 5.7 .1 PSGallery Pester is the ubiquitous test…
版本锁定与依赖管理 在自动化管道和多人协作的项目中,模块版本的一致性至关重要。不同开发者或不同环境如果安装了不兼容的模块版本,可能导致脚本行为不一致甚至运行失败。PSResourceGet 提供了多种版本控制机制来应对这一问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 Install-PSResource -Name 'Az.Accounts' -Version '3.0.0' -Scope CurrentUserInstall-PSResource -Name 'Az.Accounts' -Version '[3.0.0, 4.0.0)' -Scope CurrentUserInstall-PSResource -Name 'Pester' -Version '6.0.0' -Prerelease -Scope CurrentUser$resource = Find-PSResource -Name 'Az.Compute' -Repository 'PSGallery' $resource .Dependencies | Format-Table Name, VersionRange -AutoSize $installed = Get-InstalledPSResource $lockData = $installed | ForEach-Object { [PSCustomObject ]@ { Name = $_ .Name Version = $_ .Version } } $lockData | ConvertTo-Json -Depth 3 | Set-Content -Path './modules.lock.json' -Encoding UTF8$lock = Get-Content -Path './modules.lock.json' -Raw | ConvertFrom-Json foreach ($entry in $lock ) { Install-PSResource -Name $entry .Name -Version $entry .Version -Scope CurrentUser -ErrorAction SilentlyContinue }
这段代码展示了几个关键的版本管理技巧:使用 RequiredVersion 精确锁定版本,使用 NuGet 版本范围语法控制兼容范围,通过 Dependencies 属性分析模块的依赖树,以及将环境状态导出为 JSON 锁定文件以便在另一台机器上复现。
执行结果示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Name VersionRangeAz.Accounts [3.0 .0 , 4.0 .0 ) modules.lock .json 内容示例: [ { "Name": "Pester", "Version": "5.7.1" }, { "Name": "Az.Accounts", "Version": "3.0.0" }, { "Name": "Az.Compute", "Version": "7.0.0" } ]
私有仓库搭建与内网分发 在企业环境中,出于安全审计或网络隔离的需要,通常不希望服务器直接访问公网的 PowerShell Gallery。搭建私有仓库可以解决这个问题,同时也能用于分发团队内部开发的模块。NuGet.Server 是一种轻量级的私有仓库方案,配合 PSResourceGet 可以实现完整的内网分发流程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 Register-PackageSource -Name 'NuGetGallery' -Location 'https://www.nuget.org/api/v2' -ProviderName NuGet -Trusted $sitePath = 'C:\PSGallery\Private' New-Item -ItemType Directory -Path $sitePath -Force Save-Package -Name NuGet.Server -Source 'NuGetGallery' -Path $sitePath $modulePath = 'C:\Modules\MyUtils' $nupkgOutput = 'C:\PSGallery\Packages' Publish-PSResource -Path $modulePath -Repository 'MyCompanyFeed' -ApiKey 'your-api-key-here' Register-PSResourceRepository -Name 'CompanyGallery' -Uri 'https://psgallery.mycompany.com/v3/index.json' -Trusted Set-PSResourceRepository -Name 'CompanyGallery' -Priority 1 Find-PSResource -Name 'MyUtils' -Repository 'CompanyGallery' Install-PSResource -Name 'MyUtils' -Repository 'CompanyGallery' -Scope CurrentUserGet-InstalledPSResource -Name 'MyUtils' | Select-Object Name, Version, Repository
上述代码分为服务端和客户端两部分。服务端负责搭建 NuGet.Server 并发布内部模块,客户端则注册私有仓库、设置优先级,并从中安装模块。通过设置 Priority 参数,可以确保私有仓库中的模块优先于公网同名模块被使用,这在覆盖公网模块的场景中非常有用。
执行结果示例:
1 2 3 4 5 6 7 ---- ------- ---------- ----------- . . ---- ------- ---------- . .
注意事项
PSResourceGet 与 PowerShellGet 的兼容性 :PSResourceGet 可以管理由 PowerShellGet v2/v3 安装的模块,但反向操作可能存在兼容性问题。建议在团队内统一使用 PSResourceGet,避免混用导致的版本记录混乱。
版本范围语法 :PSResourceGet 使用 NuGet 版本范围语法,方括号表示包含边界、圆括号表示排除边界。例如 [1.0.0, 2.0.0) 表示大于等于 1.0.0 且小于 2.0.0。务必仔细检查范围表达式,避免因语法错误导致意外安装了不兼容的版本。
模块锁定文件应纳入版本控制 :modules.lock.json 类似于 npm 的 package-lock.json,应与项目代码一起提交到 Git 仓库。这样可以确保 CI/CD 管道中的模块版本与开发环境完全一致。
私有仓库的安全加固 :生产环境的私有仓库应启用 HTTPS、配置 API Key 认证,并定期审计已发布的模块内容。对于高安全要求的环境,可以考虑使用 Azure Artifacts 或 JFrog Artifactory 等企业级制品仓库。
离线环境的模块分发 :对于完全隔离的网络环境,可以使用 Save-PSResource 将模块及其依赖下载到本地目录,然后通过 U 盘或内部文件共享拷贝到目标机器,再用 Install-PSResource 从本地路径安装。这种方式不需要搭建完整的 NuGet 服务。
模块依赖冲突排查 :当遇到模块加载冲突时,可以使用 Get-Module -ListAvailable 查看所有可用版本,结合 $env:PSModulePath 分析模块搜索路径的优先级。对于冲突严重的环境,考虑使用 PowerShell 的 Assembly Load Context(ALC)隔离机制,或在不同项目中使用独立的模块安装路径。