PowerShell 7 源码仓库全解析:从 README 导读到跨平台构建、测试与版本生成的源码级实践
【免费下载链接】PowerShellPowerShell for every system!项目地址: https://gitcode.com/GitHub_Trending/po/PowerShell
本文以 PowerShell 仓库根目录的 README.md 为骨架,系统梳理 PowerShell(7.x 及更高版本)这一跨平台(Windows、Linux、macOS)自动化与配置框架的定位、与 Windows PowerShell 5.1 的边界关系、源码仓库结构、基于build.psm1模块的构建与测试流程,以及版本号的生成机制。读完本文,你将能够独立克隆并编译该仓库、定位三大平台各自的顶层构建项目,理解pwsh可执行文件的产出路径、测试入口,以及发布版本号是如何从 Git tag 推导出来的。
一、PowerShell 是什么:跨平台自动化与配置框架
README 对 PowerShell 的定义是:一个跨平台(Windows、Linux 和 macOS)的自动化与配置工具/框架,能与现有工具良好协作,并针对处理结构化数据(JSON、CSV、XML 等)、REST API 和对象模型做了优化。它由三部分组成:
- 一个命令行 Shell;
- 一门配套的脚本语言;
- 一套用于处理 cmdlet 的框架。
从源码结构看,这三部分在仓库中都有明确落点:src/System.Management.Automation/(引擎、解释器、解析器、宿主接口、远程处理等核心实现)、src/Microsoft.PowerShell.Commands.*(各命令模块,如 Utility、Security、Diagnostics、Management)、src/Microsoft.PowerShell.ConsoleHost/(控制台宿主)。仓库定位也由此清晰:这不是一个单纯的脚本集合,而是一个完整的 .NET 宿主 + 语言引擎 + 命令框架的代码库。
需要强调的是运行入口。跨平台宿主项目的 .NET CLI 入口是 src/powershell/Program.cs,其中ManagedPSEntry.Main在 UNIX 平台会先执行AttemptExecPwshLogin(处理 pwsh 作为登录 Shell 启动时的 login 逻辑),随后委托给UnmanagedPSEntry.Start进入原生宿主。该入口文件被两个顶层项目共享引用(见下文构建章节)。
二、Windows PowerShell vs. PowerShell 7+:版本边界
README 中一段容易被忽略但极其重要的说明:
虽然本仓库最初是 Windows PowerShell 代码库的分支,但在此仓库中所做的更改不会移植回 Windows PowerShell 5.1。也就是说,仓库中跟踪的 issue 只针对 PowerShell 7.x 及更高版本。Windows PowerShell 特有的问题应通过 Feedback Hub(分类选择 "Apps > PowerShell")上报。
这带来两条实操结论:
- 你在本仓库看到的任何行为、任何修复,都只影响 PowerShell 7+;5.1 的问题与本仓库无关;
- 仓库内的代码(例如引擎、cmdlet、格式数据)只描述 7.x 的行为,不能拿它反推 5.1 的表现。
三、获取与升级 PowerShell
README 给出的安装与升级建议:
- 支持平台:Windows、macOS 以及多种 Linux 发行版,官方安装文档见 Microsoft Learn 的 Installing PowerShell 主题(本仓库不重复给出外部链接);
- 升级原则:为了获得最佳结果,升级时应使用与首次安装时相同的安装方式;每种平台和每种安装方式的更新途径都不同。
这一原则在仓库的构建/打包工具链中也有对应:tools/目录下维护了各平台的安装脚本,如 tools/install-powershell.sh、tools/install-powershell.ps1 以及面向各发行版的脚本(installpsh-debian.sh、installpsh-redhat.sh、installpsh-osx.sh、installpsh-suse.sh、installpsh-amazonlinux.sh等)。"安装方式与升级方式一致"的实质,就是避免包管理器安装的版本被 tarball 覆盖、或反向冲突。
四、克隆源码仓库
README 给出的仓库获取方式是git clone。对于开发者而言,配合 docs/git/README.md 中的仓库工作指南(分支、PR 流程等)使用。克隆完成后应进入仓库根目录,后文所有构建步骤均假设你在该目录执行。
五、仓库结构速览:从 README 链接到真实目录
README 通过链接串联了多个子文档,把它们展开后就是本仓库的核心地图:
| 目录/文件 | 作用 |
|---|---|
| src/ | 全部源码。核心引擎 src/System.Management.Automation/(engine/parser/help/namespace 等子目录),命令模块 src/Microsoft.PowerShell.Commands.Utility/、src/Microsoft.PowerShell.Security/ 等,宿主 src/Microsoft.PowerShell.ConsoleHost/,入口 src/powershell/Program.cs,SDK 聚合项目 src/Microsoft.PowerShell.SDK/ |
| src/powershell-unix/、src/powershell-win-core/ | Linux/macOS 与 Windows 两个顶层构建项目(详见第七节) |
| src/Modules/ | 随构建输出的模块(按 Shared/Unix/Windows 分层) |
| tools/ | 构建辅助、打包(packaging/、releaseTools相关)、安装脚本、性能与 CI 工具 |
| test/ | Pester 测试(test/powershell/)、xUnit 测试(test/xUnit/)、宿主测试(test/hosting/)、打包测试(test/packaging/)等 |
| docs/building/ | 三大平台构建指南 + 构建过程内部机制 docs/building/internals.md |
| docs/FAQ.md | 开发者 FAQ,构建遇到问题时的第一站 |
| docs/community/governance.md | 项目治理政策 |
| build.psm1 | 构建模块,Start-PSBuild等函数的真实定义处(CI 上执行的就是它) |
| PowerShell.sln | Visual Studio 解决方案文件 |
| LICENSE.txt | MIT 许可声明 |
另外两个根目录配置文件值得注意:
- global.json:固定 .NET SDK 版本,当前为
11.0.100-preview.6.26359.118。docs/building/windows-core.md 也明确指引"当前使用的版本见仓库根目录 global.json 第 3 行"; - DotnetRuntimeMetadata.json:描述 SDK 渠道(channel/quality/qualityFallback)与 SDK 镜像版本,供
Start-PSBootstrap等引导函数下载安装 SDK 时使用。
六、构建 PowerShell:build.psm1 模块全流程
README 的 "Building PowerShell" 小节以一张三列表格给出三大平台指南:Linux 见 docs/building/linux.md、Windows 见 docs/building/windows-core.md、macOS 见 docs/building/macos.md,并提示构建问题先查开发者 FAQ。下面把这三份指南的共同主线串成一条可复制的操作路径。
6.1 引导环境:Start-PSBootstrap
构建脚本本身是 PowerShell 代码,因此需要先装一份自宿主 PowerShell。Linux 上最简单的做法(docs/building/linux.md):
./tools/install-powershell.sh pwsh然后在 PowerShell 中导入仓库根目录的构建模块 build.psm1 并引导:
Import-Module ./build.psm1 Start-PSBootstrap -Scenario Both从源码结构看,Start-PSBootstrap定义于 build.psm1 第 2848 行附近,其文档化行为如下:
- Linux:通过
apt-get(或等效包管理器)安装构建依赖与打包工具,并下载安装 .NET SDK 到~/.dotnet; - macOS:使用
brew或port安装 OpenSSL 与 GNU WGet,卸载旧版 .NET CLI,再安装 .NET Core SDK 到~/.dotnet(docs/building/macos.md); - Windows:
Start-PSBootstrap -Scenario Dotnet或等效的Install-Dotnet会移除旧版 .NET CLI 并安装本仓库依赖的版本(docs/building/windows-core.md)。
如果要在使用Start-PSBuild之外直接调用dotnet,需把~/.dotnet加入PATH。
6.2 执行构建:Start-PSBuild
三个平台指南给出的构建命令高度一致(均带-UseNuGetOrg):
# Linux / macOS Import-Module ./build.psm1 Start-PSBuild -UseNuGetOrg # Windows(建议附加清理与模块还原) Start-PSBuild -Clean -PSModuleRestore -UseNuGetOrgREADME 与三份平台指南均带有一条重要提示:PowerShell 项目默认引用私有 Azure Artifacts 源,需要认证;-UseNuGetOrg参数会把构建重新配置为使用公共 NuGet.org 源。外部贡献者基本都需要带上该参数。
Start-PSBuild定义于 build.psm1 第 336 行附近。构建完成后,它会打印可执行文件位置。按 docs/building/linux.md 的当前说明,Linux 上的产物是:
./src/powershell-unix/bin/Debug/net11.0/linux-x64/publish/pwsh该路径遵循统一形式:./[project]/bin/[configuration]/[framework]/[rid]/publish/[binary name]。以 Windows 为例(docs/building/windows-core.md),默认 Debug 配置、win-x64RID 下为./src/powershell-win-core/bin/.../publish/pwsh.exe;build.psm1 中的Get-PSOutput(第 1428 行附近)返回可执行文件路径,因此可以直接& (Get-PSOutput)运行你刚构建的 pwsh 副本。
6.3 顶层项目与"哑依赖"
为什么dotnet build一个目录就能构建整个 PowerShell?答案在 docs/building/internals.md:
- 构建命令实际执行于
$Top目录:Windows 为src/powershell-win-core,Linux/macOS 为src/powershell-unix; - 顶层项目通过**哑依赖(dummy dependencies)**串联所有程序集:例如
src/powershell-win-core/powershell-win-core.csproj声明了对Microsoft.PowerShell.Commands.Diagnostics.csproj的引用,但实际并无真实构建依赖,目的是"只构建 $Top 一个文件夹"即可传递拉起全部组件; - 规则:凡是属于 CoreCLR 构建的程序集,都应列为
$Top项目的依赖。
对照两个顶层工程文件可以印证这一结构:
- src/powershell-unix/powershell-unix.csproj:
AssemblyName为pwsh,RuntimeIdentifiers为linux-x64;osx-x64;,编译包含..\powershell\Program.cs(共享入口),并将..\Modules\Unix\**、..\Modules\Shared\**、PSMaml 帮助 Schema、LICENSE.txt、ThirdPartyNotices.txt、默认帮助assets/default.help.txt与dsc/资源一并拷贝到发布输出; - src/powershell-win-core/powershell-win-core.csproj:同样的
pwsh命名与共享Program.cs,RuntimeIdentifiers为win-x86;win-x64,额外引用了 Diagnostics、CimCmdlets、WSMan.Management 等 Windows 专属模块,并拷贝assets/GroupPolicy/下的策略模板(PowerShellCoreExecutionPolicy.admx/adml)等内容。
两个工程都启用了 TieredCompilation 及 QuickJit 优化(TieredCompilationQuickJit等开关),以加速启动期的 JIT。
6.4 构建前置步骤:ResGen 与 Type Catalog
internals 文档 还揭示了两个不需要 PowerShell、可用dotnet手动执行的预构建步骤(Start-PSBuild会自动通过Start-ResGen与Start-TypeGen调用它们,二者定义于 build.psm1 第 3292、3254 行附近):
ResGen(src/ResGen/Program.cs):为每个项目的resources目录中的*.resx文件生成强类型 C# 资源访问类,写入对应的gen目录。这些文件不会每次构建自动更新(否则破坏增量重编译);拉取新提交后若报"缺少字符串",通常需要删除gen目录重跑:
cd src/ResGen dotnet restore dotnet runType Catalog(src/TypeCatalogGen/):生成用于辅助类型解析的 C# 类型目录源文件CorePsTypeCatalog.cs(写入System.Management.Automation项目)。若构建时出现The name 'InitializeTypeCatalog' does not exist in the current context错误,即说明该源文件缺失,需按 docs/building/internals.md 中的步骤手动生成powershell.inc并运行 TypeCatalogGen。
6.5 原生组件的 NuGet 化
docs/building/internals.md 解释了另一项关键设计:原生组件被包装成 NuGet 包,避免每次构建都重新编译——
- Windows 的 WinRM 插件
pwrshplugin.dll打包为psrp.windows,事件跟踪程序集打包为PowerShell.Core.Instrumentation(清单位于 src/PowerShell.Core.Instrumentation/); - Linux/macOS 依赖
libpsl-native.so/libpsl-native.dylib(src/libpsl-native/),打包为libpsl,linux-x64二进制需在 CentOS 7 上构建以保证 glibc 可移植性; - 使用
Start-BuildNativeWindowsBinaries/Start-BuildNativeUnixBinaries构建,linux-arm需要先用Start-PSBootstrap -BuildLinuxArm安装前置依赖。
从源码结构看,这意味着日常Start-PSBuild只是消费这些二进制包;只有改动原生代码时才需要走上游的打包-发布流程。
6.6 版本号如何生成:git describe 驱动
这是一个文档未展开、但 PowerShell.Common.props 里写得非常完整的机制,直接影响每个构建产物的版本号:
- 目标
GetPSCoreVersionFromGit在Restore/Pack/Build之前执行,运行git describe --abbrev=60 --long,得到形如v7.x.x-N-g<sha>的字符串; - 未打 ReleaseTag 的日常构建:版本号取最近 tag + "Commits: N" + SHA,生成
InformationalVersion形如7.x.x Commits: 5 SHA: abc1234; - 指定
ReleaseTag(如7.2.0-rc.1)时:按正则解析,7.2.0→ 文件版本7.2.0.500(GA 增量 500);7.2.0-preview.1→7.2.0.1;RC 的迭代号从 100 起递增(7.2.0-rc.1→7.2.0.101);AssemblyVersion的 Build 段固定为 0,使服务性发布不改变程序集版本; - 应用图标也会随版本渠道切换:preview 版用
Powershell_av_colors.ico,daily 版用Powershell_avatar.ico,正式版用Powershell_black.ico(图标源文件见 assets/ 目录)。
理解这一点后,你就能解释为什么 CI 日常构建的pwsh版本号带 "Commits: N" 后缀,而 RC 构建的 FileVersion 会出现 .101、.102 这样的迭代。
七、测试:Pester 与 xUnit 双轨
三份平台构建指南在构建成功后都给出了相同的测试入口:
Start-PSPester -UseNuGetOrg # 跨平台 Pester 测试 Start-PSxUnit # xUnit 测试Start-PSPester定义于 build.psm1 第 1686 行附近,驱动的是 test/powershell/ 下的 Pester 用例,覆盖engine/、Language/、Modules/、Provider/、Host/等目录,是 PowerShell 功能测试的主战场;Start-PSxUnit定义于第 2492 行附近,运行 test/xUnit/ 下的 .NET 单元测试(csharp/子目录),面向引擎层面的断言;- 另有 test/hosting/(宿主 API 测试)、test/packaging/(分平台打包测试)、test/perf/(性能基准)。
测试布局本身(test/powershell/engine等按引擎、语言、模块、提供程序分目录)也印证了 README 所描述的"Shell + 脚本语言 + cmdlet 框架"三大件的组织方式。
八、社区、治理与安全
README 的后半部分定义了参与本项目的规范与渠道,写作时应一并继承:
- 贡献:从 CONTRIBUTING 指南 开始;为 .NET Core/C# 应用开发 PowerShell 集成时,可查 docs/FAQ.md 中关于 PowerShell SDK NuGet 包的章节;设计层面的提案见 PowerShell-RFC 仓库(外部仓库,本文不附链接);
- 讨论与聊天:GitHub Discussions 用于与代码无关的开放讨论,issue 保持可执行;社区频道包括 Discord、Libera.Chat 的 IRC 与 Slack;
- 治理:项目治理政策见 docs/community/governance.md;
- 行为准则:CODE_OF_CONDUCT.md;
- 安全策略:.github/SECURITY.md;
- 许可:MIT 许可,见 LICENSE.txt。
两点与"使用本仓库产物"直接相关的补充:
- 容器镜像:README 特别注明,PowerShell 容器镜像已转交 .NET 团队维护,
mcr.microsoft.com/powershell下的容器目前不再维护——用容器化方案前请先确认镜像来源; - 遥测:PowerShell 会采集遥测数据,细节以官方
about_Telemetry主题文档为准。
九、小结:按本文路径跑通一次构建
把全文要点压缩成一条最短路径:
- 克隆仓库并进入根目录(Git 工作流参考 docs/git/README.md);
./tools/install-powershell.sh(Linux)安装自宿主 pwsh,pwsh进入;Import-Module ./build.psm1后Start-PSBootstrap -Scenario Both安装 .NET SDK(版本以 global.json 为准,当前 11.0.100-preview.6.26359.118);Start-PSBuild -UseNuGetOrg构建,产物位于./src/powershell-unix/bin/Debug/net11.0/linux-x64/publish/pwsh(Linux);Windows 对应src/powershell-win-core下的pwsh.exe;& (Get-PSOutput)直接运行自构建副本;- 用
Start-PSPester/Start-PSxUnit跑测试; - 遇到版本或类型目录报错,回到第六节 6.4/6.6 的 ResGen、Type Catalog 与 git describe 机制定位。
本文所有命令、路径与版本事实均以当前仓库内容为准:构建指南位于 docs/building/,构建模块为 build.psm1,版本生成逻辑见 PowerShell.Common.props,内部机制详见 docs/building/internals.md。
【免费下载链接】PowerShellPowerShell for every system!项目地址: https://gitcode.com/GitHub_Trending/po/PowerShell
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考