最近在用 PowerShell 的时候,发现一些地方特别有意思。于是就萌生了看源代码的想法,单看肯定不过瘾,调试起来才有意思。于是就有了这个,记录下。
调试 PowerShell 主要分为两种方式:通过 VS 直接编译运行源代码和通过 WinDbg 来调试。
由于 PowerShell 跨平台的特性,由于我目前只有 Windows 的诉求,所以以下内容将围绕 Windows 来进行。其他平台可以参照官方文档,可以在这里看到:
PowerShell/docs/building at master · PowerShell/PowerShell
准备工作 拉代码第一步自然就是去 github 把代码 clone 下来了。地址是:
https://github.com/PowerShell/PowerShell
截至到2022年7月16日,建议不要直接直接用 master 分支,根据文档介绍,master 分支为最新版本,并非稳定版本。也就是我们平常看到的 preview 的版本。而且,这里强烈建议不用是因为目前 preview 的版本已经切换到 .net 7 了,而 .net 7 的 sos 我没找到(如果知道怎么找到的小伙伴可以告诉我,感谢~)。所以我这里是采用最新的稳定版,也就是 7.2.5 版本的源代码进行。
准备环境第二步就是准备好编译环境。因为 PowerShell 全部是 C# 实现的,自然就是依赖 dotnet 环境的了。
官方给了我们一个非常好的脚本,非常便利,在源代码的根目录下执行:
Import-Module ./build.psm1
Start-PSBootstrap
或者直接:
Install-Dotnet
就可以完成安装了。
如果只是这样,就结束了,是不是过于顺利了,就没有这篇文章的必要了。
由于我安装了 VS2022 preview 的版本,它顺带帮我安装了 .net 6.0.400-preview.22330.6 的版本,而且还不让卸载。因此我最新的版本始终是 6.0.400-preview,后续的编译,它就死命安装不了要的版本。也就是 6.0.203。
于是就只能从 dot.net 手动下载安装了。
方式一:通过 WinDbg 调试这种方式适用于不想安装 VS,但需要详细调试的同学。(不要问我为啥不用 VSC,看代码 VSC 确实不错,但调试,还得 WinDbg 来)
编译代码这里我们直接采用官方推荐的方式:
Import-Module ./build.psm1
Start-PSBuild
然后就出现下面的错误:
VERBOSE: In Find-DotNet
WARNING: The 'dotnet' in the current path can't find SDK version 6.0.203, prepending C:\Users\frend\AppData\Local\Microsoft\dotnet to PATH.
WARNING: The currently installed .NET Command Line Tools is not the required version.
Installed version: 6.0.400-preview.22330
Required version: 6.0.203
Fix steps:
1. Remove the installed version from:
- on windows '$env:LOCALAPPDATA\Microsoft\dotnet'
- on macOS and linux '$env:HOME/.dotnet'
2. Run Start-PSBootstrap or Install-Dotnet
3. Start-PSBuild -Clean
可是我明明安装了的呀:
- dotnet --list-sdks
6.0.203 [C:\Program Files\dotnet\sdk]
6.0.302 [C:\Program Files\dotnet\sdk]
6.0.400-preview.22330.6 [C:\Program Files\dotnet\sdk]
于是,就去找了下对应的脚本。在 [ps code root]/build.psm1 文件中的 Start-PSBuild → Find-Dotnet → Get-LatestInstalledSDK
function Get-LatestInstalledSDK {
Start-NativeExecution -sb {
dotnet --list-sdks | Select-String -Pattern '\d*.\d*.\d*(-\w*\.\d*)?' | ForEach-Object { [System.Management.Automation.SemanticVersion]::new($_.matches.value) } | Sort-Object -Descending | Select-Object -First 1
} -IgnoreExitcode 2> $null
}
好家伙,直接就是拿最新的作为我安装的版本,所以导致匹配不上,无法开始编译。由于我这里安装了 6.0.203 的,所以我就修改了下。根据我的安装情况,改成让他返回我想要让他返回的版本了(如下加粗版本)。这里需要根据自己实际情况修改!!!
dotnet --list-sdks | Select-String -Pattern '\d*.\d*.\d*(-\w*\.\d*)?' | ForEach-Object { [System.Management.Automation.SemanticVersion]::new($_.matches.value) } | Sort-Object -Descending | Select-Object -First **3 | Sort-Object | Select-Object -First 1**
于是我们重来一遍导入,编译。就能成功啦!
然后就能找到啦 ./src/powershell-win-core/bin/Debug/net6.0/win7-x64/publish/pwsh.exe
调试代码打开 WinDbg preview → Launch executable(advanced)
Executable 中填入上一步编译出来的地址,我的是这样的:C:\Users\frend\source\repos\dotnet\PowerShell\src\powershell-win-core\bin\Debug\net6.0\win7-x64\pwsh.exe
Arguments,填入你想调试的命令就好啦。我的是:ex bypass -nop -Command Invoke-webRequest www.baidu.com
其他就可以不管了。来,开始调试~