Windows 下如何偵錯 PowerShell

2022-07-17 06:00:27

背景

最近在用 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

其他就可以不管了。來,開始偵錯~