经典背景介绍:这一切的背景还是因为最近实习离职了之后用回了windows开发,windows上面的tree命令感觉实在是不好用,因为不能控制
-L深度,几番求索之后没找到一个喜欢的命令,最后决定是自己写一个工具命令,经过调试之后觉得还不错挺好用的,然后我就在想能不能跟npm包一样发布到大家都可用的那种社区平台上,然后我找到了powershell gallery.
创建Powershell Gallery账户
点此创建账户👉:https://PowerShellGallery.com
看到这里就说明创建完成:

然后点击用户名选择API Keys,创建一个新的api-key:

然后get到key:

使用PSScriptAnalyzer
这是微软官方文档建议完成的优先级第一的步骤: 使用PSScriptAnalyzer识别PowerShell代码中最常见的问题,并且通常会提供有关如何解决问题的建议。
1. 安装 PSScriptAnalyzer
1 | Install-Module PSScriptAnalyzer -Scope CurrentUser |
查看版本:
1 | Get-Module PSScriptAnalyzer -ListAvail |
2. 对脚本进行扫描
比如这是我的脚本路径:
1 | D:\TreeView-PS\TreeView.ps1 |
1 | Invoke-ScriptAnalyzer -Path "D:\TreeView-PS\TreeView.ps1" |
会输出类似:
1 | RuleName Severity Line Message |

参考这里的问题把问题都解决。直到使用扫描命令无输出。
3. 对整个模块扫描
如果你组织成模块结构:
1 | TreeView/ |
运行:
1 | Invoke-ScriptAnalyzer -Path "TreeView" -Recurse |
4. 自动修复(如果可能)
1 | Invoke-ScriptAnalyzer -Path .\TreeView.ps1 -Fix |
不是所有规则都能自动修,但能自动 fix 的就会帮你处理。
5. 发布前自动检查
可以在发布前先跑:
1 | Invoke-ScriptAnalyzer -Path . -Recurse -Severity Warning,Error |
如果未来用 GitHub Actions 发布模块,可以加:
.github/workflows/lint.yml:
1 | name: Lint PowerShell |
使用Pester进行单元测试
安装现代版本的Pester
Windows 10 / Windows Server 2016 及更高版本预装了 Pester 3.4.0 版本。此内置版本无法使用简单的Update-Modulecmdlet 进行更新。您需要执行并行安装才能开始使用最新版本的 Pester。
内置版本由微软签名,而较新的版本由社区维护并使用不同的证书签名,这Install-Module有时会导致出现错误,要求我们接受新的发布者证书。
首先安装Pester 5.x 现代版本,由于系统里预置了不再更新的3.x, 所以安装新版应当使用参数跳过系统检查:
1 | Install-Module -Name Pester -Force -Scope CurrentUser -SkipPublisherCheck |
安装完成之后可以用此命令验证版本:
1 | Get-Module -ListAvailable Pester |

看到有了5.7.1就说明就绪了,然后最好是卸载已加载的Pester3,否则不会用5.x版本,运行下面命令卸载靠前的版本并手动加载新版(5.0.0以后的版本):
1 | Remove-Module Pester -Force -ErrorAction SilentlyContinue |
现在再看一下当前模块版本:
1 | (Get-Module Pester).Version |
1 | PS D:\TreeView-PS> (Get-Module Pester).Version |
执行测试
然后准备好测试脚本,项目目录如:
1 | D:\TreeView-PS |
在仓库根目录执行:
1 | # 运行目录下所有测试 |
效果如下:

一个测试内部模块未导出的function的方法
在真实模块设计中,不推荐导出内部函数(Private Functions)。
例如 Get-Icon / Get-Color 这类内部辅助函数不应该成为模块的对外 API。
如果你的测试脚本里试图访问模块内的函数但却没有导出,可能会出现如下报错:
1 | CommandNotFoundException: 无法将“Get-Color”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。 |
可以采用这个办法–Dot Source:
1 | BeforeAll { |
测试覆盖率报告
如需同时生成覆盖率,可以参考这个文档:Generating Code Coverage Metrics | Pester
贴一个例子:
1 | # Create a Pester configuration object using `New-PesterConfiguration` |
我查看了一下为自己的覆盖率:
1 | Starting discovery in 1 files. |
可以看到我这个分支覆盖率还很低,不过这并不是本博客的重点,至于提高覆盖率可以通过其他的手段来实现。
推送到Powershell Gallery
注册 PowerShell Gallery API Key
还记得我们之前是有得到了一个api-key的,你应当已经将这个api-key给记在某处。
生成psd1(打包)
使用下列命令:
1 | New-ModuleManifest -Path ./TreeView.psd1 ` |
生成的psd1内容像这样:
1 | @{ |
给他改吧改吧,把信息填一填.
你可以选择手动发布(简单好操作)
1 | Publish-Module -Path .\ -Repository PSGallery -NuGetApiKey '<your-api-key>' |
Publish-Module命令详解
1. Publish-Module
PowerShell 内置的发布命令,用来把一个模块上传到 PowerShell Gallery。
一般你的模块目录结构如下:
1 | TreeView-PS/ |
只要有 .psd1 就可以发布。
2. -Path .
代表“当前路径就是我要发布的模块目录”。
你的执行目录一般就是模块根目录,所以写 . 就够了。
如果放模块在子目录,可能要写成:-Path ./src/TreeView
3. -Repository PSGallery
指定发布目标仓库,就是官方 PowerShell Gallery。
你也可以发布到私有 NuGet 服务器,但你现在用的是默认的公共仓库。
4. -NuGetApiKey <your-api-key>
这是发布到 Gallery 的 登录凭证。
PowerShell Gallery 使用 NuGet API Key 鉴权,也就是我们在Powershell Gallery申请的key。
所以整句命令的意思是:
使用 GitHub Actions 自动将当前目录的 PowerShell 模块上传到 PowerShell Gallery,
使用存放在环境变量中的 NuGet API Key 认证,并发布。
使用GitHub Actions实现CI/CD(推荐)
CI/CD 代表持续集成 (Continuous Integration)和持续交付/部署 (Continuous Delivery/Deployment),是一种软件开发方法,通过自动化构建、测试和部署流程,实现更快、更频繁地向客户交付高质量的软件。持续集成 (CI) 侧重于开发人员频繁将代码集成到共享存储库并进行自动化测试;而持续交付/部署 (CD) 则在此基础上,自动化将变更交付到生产环境的过程。
若要使 GitHub 在存储库中发现任何 GitHub Actions 工作流,必须将工作流文件保存在名为 .github/workflows 的目录中。
你可以为工作流文件指定所需的任何名称,但必须使用 .yml 或 .yaml 作为文件扩展名。 YAML 通常是用于配置文件的标记语言。
– Github官方文档
Github建仓
- 在Github上创建仓库
建一个仓库记住url,如:https://github.com/你的账号/<仓库名字>.git
- 本地初始化git并推送
1 | git init # 如果还没初始化过 |
使用Github Action
你需要先来到网页端,给你的仓库配置一个专用的 API Key。创建方法如图:

这个时候就把刚刚存的API Key拿出来就行,然后给他命名,以后用得上,我这里命名为:
1 | PSGalleryApiKey |

在项目根目录下创建./github/workflows/main.yml,github的教程提供了一个模板,下面以我的方法为例解释ci/cd 工作流文件:
1 | name: PowerShell Module CI/CD |
- checkout:拉取仓库代码
- setup PowerShell:确保 Windows runner 安装 PowerShell
- 安装 Pester:最新版本
- 运行单元测试:确保模块没有问题
- 发布模块:
- 只在 main 分支 push 时触发
- 使用仓库 Secrets 中的 PSGalleryApiKey
-Force会覆盖同版本模块,如果你想严格控制版本可以改成自动生成新版本
push后自动执行流程
如下图,找到正在执行的workflow:

等待执行成功或失败。
然后我们可以看到这里有一个失败是啥呢,是这个-f支路没有成功:

No valid module was found
1 | Line | |

这个报错是因为仓库无合法模块,注意合法的ps模块必须是这样的结构,你只能用子文件夹作为目录,不能用根:
1 | <ModuleName>/ |
只要把Publish-Module -Path . -NuGetApiKey $env:PSGalleryApiKey -Repository PSGallery -Force改成Publish-Module -Path ./<结构正确的子文件夹> -NuGetApiKey $env:PSGalleryApiKey -Repository PSGallery -Force
经过坚持不懈的调试终于发布成功。

参考文档
ps!推荐一个可以用来快速获得md link的浏览器插件:Copy as Markdown
PowerShell 库发布指南和最佳做法 - PowerShell | Microsoft Learn
PowerShell - 如何在 Pester v5 中处理点源? - Stack Overflow