PowerShell 技能连载 - PowerShell Gallery 发布

适用于 PowerShell 5.1 及以上版本

PowerShell Gallery(www.powershellgallery.com)是微软官方维护的 PowerShell 模块和脚本共享平台,类似于 Node.js 的 npm 或 Python 的 PyPI。通过它,你可以将自己编写的模块分发给全球的 PowerShell 用户,也可以方便地安装其他人发布的工具。对于团队协作而言,将内部通用组件发布到私有 Gallery 或公开 Gallery,能够显著提升代码复用率和团队协作效率。

本文将从模块准备、API Key 管理、发布流程以及版本更新四个环节,完整介绍如何将一个自定义 PowerShell 模块发布到 PowerShell Gallery。无论你是开源项目维护者还是企业内部工具开发者,掌握这一流程都能让你的 PowerShell 代码分发更加规范和专业。

准备模块清单文件

PowerShell Gallery 要求发布的模块必须包含模块清单文件(.psd1)。清单文件中定义了模块的元数据,包括版本号、作者、描述、依赖项等信息。其中一些字段是 Gallery 发布的必填项,缺少这些字段会导致发布失败。

使用 New-ModuleManifest 可以快速创建一个标准的清单文件:

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
# 创建模块目录结构
$modulePath = Join-Path -Path $env:USERPROFILE -ChildPath "Documents\PowerShell\Modules\MyUtils"
if (-not (Test-Path -Path $modulePath)) {
New-Item -Path $modulePath -ItemType Directory -Force | Out-Null
Write-Host "已创建模块目录: $modulePath"
}

# 创建模块清单
$manifestParams = @{
Path = Join-Path -Path $modulePath -ChildPath "MyUtils.psd1"
RootModule = "MyUtils.psm1"
ModuleVersion = "1.0.0"
Author = "Your Name"
CompanyName = "Your Company"
Description = "A collection of utility functions for daily PowerShell tasks"
PowerShellVersion = "5.1"
FunctionsToExport = @("Get-SystemReport", "Invoke-HealthCheck")
CmdletsToExport = @()
VariablesToExport = @()
AliasesToExport = @()
Tags = @("Utility", "Automation", "Monitoring")
ProjectUri = "https://github.com/yourname/MyUtils"
LicenseUri = "https://github.com/yourname/MyUtils/blob/main/LICENSE"
ReleaseNotes = "Initial release with system report and health check functions."
}

New-ModuleManifest @manifestParams
Write-Host "模块清单已创建"

执行结果示例:

1
2
已创建模块目录: C:\Users\admin\Documents\PowerShell\Modules\MyUtils
模块清单已创建

清单中 TagsProjectUriLicenseUriReleaseNotes 这几个字段虽然不是 New-ModuleManifest 的必需参数,但 PowerShell Gallery 发布时会检查它们。缺失这些字段虽然不会阻止发布,但会严重影响模块在 Gallery 中的可发现性和用户体验。建议在发布前使用 Test-ModuleManifest 验证清单文件的完整性。

获取并配置 API Key

发布模块到 PowerShell Gallery 需要一个 API Key。你需要先在 powershellgallery.com 注册账户(支持 Microsoft 账户或 GitHub 账户登录),然后在账户设置中生成 API Key。API Key 本质上是一个 NuGet API Key,PowerShell Gallery 底层基于 NuGet 协议运行。

为了安全起见,不要将 API Key 硬编码在脚本中。推荐的做法是将 Key 保存到环境变量或凭据管理器中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 检查是否已配置 API Key 环境变量
if ($env:PSGALLERY_API_KEY) {
Write-Host "API Key 已配置,长度: $($env:PSGALLERY_API_KEY.Length) 个字符"
}
else {
Write-Host "尚未配置 PSGALLERY_API_KEY 环境变量"
Write-Host "请按以下步骤操作:"
Write-Host " 1. 访问 https://www.powershellgallery.com/users/account/LogOn"
Write-Host " 2. 登录后进入 API Keys 页面"
Write-Host " 3. 点击 Create 生成新的 API Key"
Write-Host " 4. 将 Key 保存为环境变量:"
Write-Host ' [Environment]::SetEnvironmentVariable("PSGALLERY_API_KEY", "your-key-here", "User")'
}

# 永久保存 API Key 到用户级环境变量(只需执行一次)
# [Environment]::SetEnvironmentVariable("PSGALLERY_API_KEY", "your-api-key", "User")

执行结果示例:

1
2
3
4
5
6
7
尚未配置 PSGALLERY_API_KEY 环境变量
请按以下步骤操作:
1. 访问 https://www.powershellgallery.com/users/account/LogOn
2. 登录后进入 API Keys 页面
3. 点击 Create 生成新的 API Key
4. 将 Key 保存为环境变量:
[Environment]::SetEnvironmentVariable("PSGALLERY_API_KEY", "your-key-here", "User")

API Key 生成时可以选择过期时间和作用域。建议使用最小权限原则:如果只需要推送特定模块,就创建限定到该模块名称的 Key,而不是创建全权限 Key。这样即使 Key 泄露,影响范围也可以控制。

一切准备就绪后,使用 Publish-Module 命令将模块发布到 PowerShell Gallery。发布前务必在本地完整测试模块功能,因为一旦发布,版本号就不可重复使用——如果你发布了 1.0.0 版本后发现 bug,只能通过发布 1.0.1 等新版本修复,无法覆盖 1.0.0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 发布前的预检查
$modulePath = Join-Path -Path $env:USERPROFILE -ChildPath "Documents\PowerShell\Modules\MyUtils"

# 验证清单文件
$manifest = Test-ModuleManifest -Path (Join-Path -Path $modulePath -ChildPath "MyUtils.psd1")
if ($manifest) {
Write-Host "模块名称: $($manifest.Name)"
Write-Host "版本号: $($manifest.Version)"
Write-Host "导出函数: $($manifest.ExportedFunctions.Keys -join ', ')"
}

# 发布模块
$publishParams = @{
Path = $modulePath
NuGetApiKey = $env:PSGALLERY_API_KEY
Repository = "PSGallery"
Verbose = $true
}

Publish-Module @publishParams
Write-Host "模块已成功发布到 PowerShell Gallery!"

执行结果示例:

1
2
3
4
5
6
7
模块名称: MyUtils
版本号: 1.0.0
导出函数: Get-SystemReport, Invoke-HealthCheck
VERBOSE: Successfully created an API key for PSGallery.
VERBOSE: Attempting to publish module 'MyUtils' version '1.0.0' to 'PSGallery'.
VERBOSE: Successfully published module 'MyUtils' version '1.0.0' to 'PSGallery'.
模块已成功发布到 PowerShell Gallery!

发布成功后,模块通常在几分钟内就能在 PowerShell Gallery 上搜索到。其他用户可以通过 Install-Module -Name MyUtils 直接安装使用。

验证发布结果

发布完成后,应当验证模块在 Gallery 上的展示效果。可以通过命令行查询,也可以在浏览器中直接访问模块页面,检查描述、标签、项目链接等信息是否正确显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 通过命令行验证模块是否已上线
$published = Find-Module -Name "MyUtils" -Repository PSGallery

if ($published) {
Write-Host "模块已上线!"
Write-Host " 名称: $($published.Name)"
Write-Host " 版本: $($published.Version)"
Write-Host " 描述: $($published.Description)"
Write-Host " 作者: $($published.Author)"
Write-Host " 下载量: $($published.AdditionalMetadata['versionDownloadCount'])"
Write-Host " 页面: https://www.powershellgallery.com/packages/$($published.Name)/$($published.Version)"
}
else {
Write-Host "警告: 未在 Gallery 中找到模块,可能需要等待几分钟"
}

执行结果示例:

1
2
3
4
5
6
7
模块已上线!
名称: MyUtils
版本: 1.0.0
描述: A collection of utility functions for daily PowerShell tasks
作者: Your Name
下载量: 0
页面: https://www.powershellgallery.com/packages/MyUtils/1.0.0

如果信息有误,可以在修正后发布新版本。已发布的版本无法修改或删除(除非联系 PowerShell Gallery 运维团队)。

更新模块版本

当模块修复了 bug 或新增功能后,需要递增版本号并重新发布。PowerShell Gallery 遵循语义化版本(SemVer)规则:主版本号.次版本号.修订号。例如,修复 bug 递增修订号(1.0.0 → 1.0.1),新增功能递增次版本号(1.0.1 → 1.1.0),不兼容的 API 变更递增主版本号(1.1.0 → 2.0.0)。

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
# 更新模块版本号和发布说明
$modulePath = Join-Path -Path $env:USERPROFILE -ChildPath "Documents\PowerShell\Modules\MyUtils"
$manifestPath = Join-Path -Path $modulePath -ChildPath "MyUtils.psd1"

# 读取当前版本并递增修订号
$currentManifest = Test-ModuleManifest -Path $manifestPath
$currentVersion = $currentManifest.Version
$newVersion = [version]::new(
$currentVersion.Major,
$currentVersion.Minor,
$currentVersion.Build + 1
)

Write-Host "当前版本: $currentVersion → 新版本: $newVersion"

# 更新清单中的版本号和发布说明
$updateData = @{
ModuleVersion = $newVersion.ToString()
ReleaseNotes = "Fixed edge case in Get-SystemReport when WMI service is stopped."
}
Update-ModuleManifest -Path $manifestPath @updateData

# 重新发布
Publish-Module -Path $modulePath -NuGetApiKey $env:PSGALLERY_API_KEY -Repository PSGallery
Write-Host "新版本 $newVersion 已发布"

执行结果示例:

1
2
3
4
当前版本: 1.0.0 → 新版本: 1.0.1
VERBOSE: Attempting to publish module 'MyUtils' version '1.0.1' to 'PSGallery'.
VERBOSE: Successfully published module 'MyUtils' version '1.0.1' to 'PSGallery'.
新版本 1.0.1 已发布

版本更新后,已安装旧版本的用户通过 Update-Module -Name MyUtils 即可获取最新版本。PowerShellGet 会自动处理版本比较和下载安装。

自动化发布流程

在 CI/CD 场景中,可以将发布流程集成到 GitHub Actions 或 Azure Pipelines 中,实现提交代码后自动发布新版本。以下是一个使用 PowerShell 脚本在 CI 环境中发布的示例:

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
36
37
38
39
40
41
42
43
44
# 适用于 CI/CD 管道的发布脚本
# 从 git tag 中提取版本号,确保版本号与代码提交严格对应
$gitTag = git describe --tags --abbrev=0 2>$null
if (-not $gitTag) {
Write-Error "未找到 git tag,请先创建版本标签"
return
}

# 从 tag 名称中解析版本号(例如 v1.2.3 → 1.2.3)
$versionStr = $gitTag -replace '^v', ""
$newVersion = [version]$versionStr

Write-Host "准备发布版本: $newVersion (from tag: $gitTag)"

# 更新清单
$manifestPath = "./src/MyUtils/MyUtils.psd1"
$releaseNotes = git log --pretty=format:"- %s" ("$($gitTag)~1"..HEAD) 2>$null
if (-not $releaseNotes) {
$releaseNotes = "Release $newVersion"
}

Update-ModuleManifest -Path $manifestPath -ModuleVersion $newVersion.ToString() -ReleaseNotes $releaseNotes

# 验证清单完整性
$requiredFields = @("Description", "Author", "Tags", "ProjectUri", "LicenseUri")
$manifest = Test-ModuleManifest -Path $manifestPath
$warnings = @()
foreach ($field in $requiredFields) {
$value = $manifest.$field
if (-not $value) {
$warnings += "缺少必填字段: $field"
}
}

if ($warnings.Count -gt 0) {
Write-Host "发布前检查警告:"
foreach ($w in $warnings) {
Write-Host " [WARN] $w"
}
}

# 发布
Publish-Module -Path "./src/MyUtils" -NuGetApiKey $env:PSGALLERY_API_KEY -Repository PSGallery
Write-Host "CI/CD 发布完成: v$newVersion"

执行结果示例:

1
2
准备发布版本: 1.1.0 (from tag: v1.1.0)
CI/CD 发布完成: v1.1.0

将 API Key 存储在 CI/CD 平台的安全变量中(如 GitHub Secrets),确保密钥不会出现在日志和代码仓库中。这种方式适合团队协作开发,每次合并代码后自动触发构建和发布。

注意事项

  • 版本号不可复用:PowerShell Gallery 不允许删除已发布的版本,也无法覆盖已有版本号。即使你发布了一个有严重 bug 的版本,该版本号也永久被占用。发布前务必在本地充分测试,确认无误后再推送。
  • 清单必填字段DescriptionAuthor 是 Gallery 的强制要求字段。虽然 TagsProjectUriLicenseUri 不阻止发布,但缺失这些字段会让模块难以被搜索和信任。建议在 New-ModuleManifest 阶段就完整填写所有字段。
  • API Key 安全管理:不要将 API Key 提交到代码仓库,也不要在聊天记录或日志中明文输出。使用环境变量或 CI/CD 平台的安全变量存储,并为不同用途创建不同作用域的 Key。
  • 模块大小限制:PowerShell Gallery 对单个模块包的大小有限制(目前约 250 MB)。如果你的模块包含大量二进制文件或数据文件,考虑使用外部存储并仅在模块中提供下载脚本。
  • 私有 Gallery 部署:企业内部可以使用 PowerShell Gallery 的私有实例(如基于 NuGet Server 或 Artifactory 搭建),发布流程完全相同,只需通过 Register-PSRepository 注册内部仓库地址,然后在 Publish-Module 中指定 -Repository 参数即可。
  • 依赖项声明:如果模块依赖其他模块,务必在清单中通过 RequiredModules 字段声明。这样用户安装你的模块时,PowerShellGet 会自动解析并安装所有依赖,避免因缺少依赖导致模块加载失败。

PowerShell 技能连载 - 自定义模块开发与发布

适用于 PowerShell 7.0 及以上版本

模块化开发的意义

当你的 PowerShell 脚本从几十行增长到几百行、甚至跨多个文件协作时,把代码组织成模块就变得尤为重要。模块(Module)是 PowerShell 中代码复用和分发的基本单元,它让你可以将相关函数、类、配置打包在一起,通过一条 Import-Module 命令即可加载使用。

PowerShell Gallery 是微软官方维护的模块仓库,社区已有超过 4000 个模块可供直接安装。将自己编写的模块发布到 PowerShell Gallery,不仅方便团队成员共享,也能让全球 PowerShell 用户受益。本文将从零开始,带你完成一个自定义模块的开发、测试与发布全流程。

规划模块目录结构

一个规范的 PowerShell 模块应当遵循统一的目录结构。模块根目录以模块名命名,内部包含模块清单文件(.psd1)、脚本模块文件(.psm1)、以及按功能分类的函数文件。此外还应包含测试目录和帮助文档。

下面是一个典型模块的目录结构示例:

1
2
3
4
5
6
7
8
9
10
11
12
MyUtils/
├── MyUtils.psd1 # 模块清单
├── MyUtils.psm1 # 模块入口
├── Private/ # 内部函数(不导出)
│ └── _ResolvePath.ps1
├── Public/ # 公开函数(导出给用户)
│ ├── Get-SystemInfo.ps1
│ └── Send-WebNotification.ps1
├── Tests/ # Pester 测试
│ └── Get-SystemInfo.Tests.ps1
└── en-US/ # 帮助文档
└── About_MyUtils.help.txt

这种将 Public 和 Private 函数分离的做法,让模块的公共 API 与内部实现解耦。用户只能调用 Public 目录下的函数,而 Private 目录下的辅助函数对用户不可见,降低了模块的使用复杂度。

创建模块清单

模块清单(.psd1)是模块的元数据文件,定义了模块的版本、作者、导出命令、依赖关系等信息。PowerShell 提供了 New-ModuleManifest cmdlet 来生成这个文件。

以下命令创建一个完整的模块清单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$modulePath = Join-Path $HOME "Documents/PowerShell/Modules/MyUtils"

New-ModuleManifest -Path (Join-Path $modulePath "MyUtils.psd1") `
-RootModule "MyUtils.psm1" `
-ModuleVersion "1.0.0" `
-Author "victorwoo" `
-Description "日常运维工具函数集" `
-PowerShellVersion "7.0" `
-FunctionsToExport @("Get-SystemInfo", "Send-WebNotification") `
-CmdletsToExport @() `
-VariablesToExport @() `
-AliasesToExport @() `
-PrivateData @{
PSData = @{
Tags = @("Utils", "SystemInfo", "Notification")
ProjectUri = "https://github.com/victorwoo/MyUtils"
LicenseUri = "https://github.com/victorwoo/MyUtils/blob/main/LICENSE"
ReleaseNotes = "首个正式版本"
}
}

执行结果示例:

1
2
3
4
5
    目录: /Users/victorwoo/Documents/PowerShell/Modules/MyUtils

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2025/4/23 08:00 2847 MyUtils.psd1

清单中 FunctionsToExport 显式指定了要导出的函数名。这是一个关键设置——如果省略此参数,PowerShell 会导出模块中所有函数,包括你原本不想公开的内部辅助函数。显式控制导出列表是模块设计的最佳实践。

编写模块入口与导出函数

模块入口文件 .psm1 负责加载所有函数文件并控制模块的初始化逻辑。一个推荐的写法是使用点 sourcing(dot sourcing)批量加载 Public 和 Private 目录下的脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# MyUtils.psm1 - 模块入口文件

# 加载 Private 函数
$privateFiles = Get-ChildItem -Path (Join-Path $PSScriptRoot "Private") `
-Filter "*.ps1" -Recurse -ErrorAction SilentlyContinue

foreach ($file in $privateFiles) {
. $file.FullName
}

# 加载 Public 函数
$publicFiles = Get-ChildItem -Path (Join-Path $PSScriptRoot "Public") `
-Filter "*.ps1" -Recurse -ErrorAction SilentlyContinue

foreach ($file in $publicFiles) {
. $file.FullName
}

接下来在 Public 目录下编写一个实用的函数 Get-SystemInfo,用于快速获取当前系统的关键信息:

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
36
37
38
39
40
41
42
# Public/Get-SystemInfo.ps1

function Get-SystemInfo {
<#
.SYNOPSIS
获取当前系统关键运行信息
.DESCRIPTION
返回操作系统版本、运行时间、内存使用率和磁盘空间等摘要信息
.EXAMPLE
Get-SystemInfo
#>
[CmdletBinding()]
param()

$os = [System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription
$uptime = (Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
$mem = Get-CimInstance Win32_OperatingSystem
$memPercent = [math]::Round(
($mem.TotalVisibleMemorySize - $mem.FreePhysicalMemory) /
$mem.TotalVisibleMemorySize * 100, 1
)

$disks = Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" |
ForEach-Object {
$free = [math]::Round($_.FreeSpace / 1GB, 1)
$total = [math]::Round($_.Size / 1GB, 1)
[PSCustomObject]@{
Drive = $_.DeviceID
Free_GB = $free
Total_GB = $total
Used_Pct = [math]::Round(($total - $free) / $total * 100, 1)
}
}

[PSCustomObject]@{
OS = $os
PowerShell = $PSVersionTable.PSVersion.ToString()
Uptime = $uptime.ToString("dd\.hh\:mm\:ss")
MemoryUsedPct = $memPercent
Disks = $disks
}
}

执行结果示例:

1
2
3
4
5
6
OS            : .NET 8.0.2
PowerShell : 7.4.1
Uptime : 03.14:22:15
MemoryUsedPct : 68.3
Disks : {Drive=C:, Free_GB=89.2, Total_GB=256.0, Used_Pct=65.2}

函数中使用了 CimInstance 而非已弃用的 WmiObject,确保在 PowerShell 7 跨平台场景下有更好的兼容性。[CmdletBinding()] 属性让普通函数获得高级函数的能力,支持 -Verbose-Debug 等通用参数。

编写 Pester 测试

模块的质量保障离不开自动化测试。Pester 是 PowerShell 社区最流行的测试框架,几乎所有的社区模块都使用它来编写单元测试。在将模块发布到 PowerShell Gallery 之前,确保测试通过是必要的步骤。

以下是为 Get-SystemInfo 编写的 Pester 测试:

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
# Tests/Get-SystemInfo.Tests.ps1

BeforeAll {
Import-Module (Join-Path $PSScriptRoot ".." "MyUtils.psd1") -Force
}

Describe "Get-SystemInfo" {
It "返回一个 PSCustomObject" {
$result = Get-SystemInfo
$result | Should -BeOfType [PSCustomObject]
}

It "包含 OS 属性且类型为字符串" {
$result = Get-SystemInfo
$result.OS | Should -BeOfType [string]
$result.OS.Length | Should -BeGreaterThan 0
}

It "包含 PowerShell 版本信息" {
$result = Get-SystemInfo
$result.PowerShell | Should -Match "^\d+\.\d+"
}

It "内存使用率在 0 到 100 之间" {
$result = Get-SystemInfo
$result.MemoryUsedPct | Should -BeGreaterOrEqual 0
$result.MemoryUsedPct | Should -BeLessOrEqual 100
}

It "返回至少一个磁盘信息" {
$result = Get-SystemInfo
$result.Disks.Count | Should -BeGreaterOrEqual 1
}
}

执行测试的命令和结果:

1
Invoke-Pester -Path ./Tests -Output Detailed

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
Starting discovery in 1 files.
Discovery found 5 tests in 12ms.
Running tests.

┌ Tests/Get-SystemInfo.Tests.ps1
│ √ Get-SystemInfo 返回一个 PSCustomObject (8ms)
│ √ Get-SystemInfo 包含 OS 属性且类型为字符串 (3ms)
│ √ Get-SystemInfo 包含 PowerShell 版本信息 (2ms)
│ √ Get-SystemInfo 内存使用率在 0100 之间 (3ms)
│ √ Get-SystemInfo 返回至少一个磁盘信息 (4ms)

Tests passed: 5, Failed: 0, Skipped: 0, NotRun: 0
Total time: 0.23s

测试覆盖了函数返回值的类型检查、属性存在性验证、以及数值范围的合理性校验。编写 Pester 测试时,应当关注函数的”契约”——即它承诺返回什么,而非内部实现细节,这样当内部逻辑优化时测试不会轻易失败。

当模块开发和测试都完成后,就可以将其发布到 PowerShell Gallery 供他人使用。发布前需要完成两个准备工作:注册 PowerShell Gallery 账号获取 API Key,以及确保模块清单中的元数据完整准确。

使用 Publish-Module 命令即可一键发布:

1
2
3
4
5
6
7
# 首先验证模块清单是否有效
Test-ModuleManifest -Path (Join-Path $modulePath "MyUtils.psd1")

# 发布到 PowerShell Gallery
Publish-Module -Path $modulePath `
-NuGetApiKey "oy2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" `
-Repository "PSGallery"

执行结果示例:

1
2
3
4
5
ModuleName      : MyUtils
ModuleVersion : 1.0.0
Published : 2025-04-23 08:00:00
PublishedBy : victorwoo
Repository : PSGallery

发布成功后,任何用户都可以通过以下命令安装和使用你的模块:

1
2
3
Install-Module -Name MyUtils -Scope CurrentUser
Import-Module MyUtils
Get-SystemInfo

需要注意的是,Publish-Module 要求模块清单中的 PrivateData.PSData 包含 TagsProjectUriLicenseUri 等字段,否则会发布失败。另外,API Key 可以在 powershellgallery.com 的账户设置页面生成,建议使用作用域限定(scoped)的 Key 而非全权限 Key,以降低安全风险。

注意事项

  • 显式导出控制:在 .psd1 中使用 FunctionsToExport 明确列出要导出的函数名,避免内部函数意外暴露。同时设置 CmdletsToExport = @()VariablesToExport = @() 等为空数组,防止默认行为导出不需要的成员。

  • 语义化版本号:模块版本遵循 Major.Minor.Patch 规则。破坏性变更升 Major,新增功能升 Minor,Bug 修复升 Patch。PowerShell Gallery 不允许重复上传同一版本号,每次发布必须递增版本号。

  • API Key 安全:不要将 NuGet API Key 硬编码在脚本中。推荐使用环境变量或 Azure Key Vault 存储,CI/CD 流水线中通过 $env:NUGET_API_KEY 传入。

  • 跨平台兼容性:如果你的模块需要在 Linux 和 macOS 上运行,避免使用 WmiObjectWin32_* 等 Windows 专属类。改用 CimInstance/proc 文件系统读取或条件分支处理平台差异。

  • CI/CD 自动化:在 GitHub Actions 或 Azure Pipelines 中集成 Pester 测试和 Publish-Module,实现提交代码后自动测试、打 Tag 后自动发布的工作流,减少人工操作带来的遗漏。