簡短描述
描述 PowerShell 調試程式。
長描述
調試是在腳本運行時檢查腳本以識別和更正腳本指令中的錯誤的過程。 PowerShell 調試器可以説明您檢查和識別腳本、函數、命令、PowerShell 工作流、PowerShell Desired State Configuration (DSC) 配置或表達式中的錯誤和低效情況。
從 PowerShell 5.0 開始,PowerShell 調試器已更新為調試在遠端電腦上的控制台或 Windows PowerShell ISE 中運行的腳本、函數、工作流、命令、配置或表達式。 您可以執行 Enter-PSSession 來啟動互動式遠端 PowerShell 工作階段,您可以在其中設定斷點,並在遠端電腦上偵錯腳本檔案和命令。
Enter-PSSession 功能已更新,允許您重新連接並進入在遠端電腦上運行腳本或命令的斷開連接的會話。 如果執行中的文稿叫用斷點,您的用戶端會話會自動啟動調試程式。 如果正在運行腳本的斷開連接的會話已經命中斷點,並在斷點處停止, Enter-PSSession 則在您重新連接到會話后自動啟動命令行調試器。
PowerShell 調試器還可用於在 PowerShell 控制台或 Windows PowerShell ISE 中調試 PowerShell 工作流。 從 PowerShell 5.0 開始,您可以在本地或遠端調試正在運行的作業或進程。
您可以使用PowerShell調試器的功能來檢查PowerShell腳本、函數、命令、工作流或表達式,前提是該腳本、函數、命令、工作流或表達式正在運行。 PowerShell 調試器包括一組 cmdlet,可用於設置斷點、管理斷點和查看調用堆疊。
Debugger Cmdlets
PowerShell 調試程式包含下列一組 Cmdlet:
-
Set-PSBreakpoint:在行、變數和命令上設定斷點。 -
Get-PSBreakpoint:取得目前會話中的斷點。 -
Disable-PSBreakpoint:關閉目前會話中的斷點。 -
Enable-PSBreakpoint:重新啟用目前會話中的斷點。 -
Remove-PSBreakpoint:從目前的會話刪除斷點。 -
Get-PSCallStack:顯示目前的呼叫堆疊。
啟動和停止調試程式
要啟動除錯器,請設置一個或多個斷點。 然後,運行要調試的腳本、命令或函數。
當您到達斷點時,執行會停止,並將控制權移交給調試程式。
要停止調試器,請運行腳本、命令或函數,直到它完成。 或者,輸入 stop 或 t。
調試程式命令
當您在 PowerShell 控制台中使用調試程式時,請使用下列命令來控制執行。 在 Windows PowerShell ISE 中,使用 [偵錯] 功能表上的命令。
注: 有關如何在其他主機應用程式中使用調試器的資訊,請參閱主機應用程式文檔。
s,StepInto:執行下一個語句,然後停止。v、StepOver:執行下一個語句,但會略過函式和調用。 跳過的語句將被執行,但不會單步執行。Ctrl+Break:( 在 ISE 中全部中斷)中斷為 PowerShell 控制台或 Windows PowerShell ISE 內執行中的腳本。 請注意,Windows PowerShell 2.0、3.0 和 4.0 中的 Ctrl+中斷 會關閉程式。 中斷全部適用於本機和遠端以互動方式執行的腳本。o,StepOut:走出目前的函式;如果巢狀,則向上增加一個層級。 如果位於主體中,它會繼續結束或下一個斷點。 跳過的語句將被執行,但不會單步執行。c,Continue:繼續執行直到腳本完成或到達下一個斷點為止。 跳過的語句將被執行,但不會單步執行。l,List:顯示正在執行的腳本部分。 根據預設,它會顯示目前的行、5 個前幾行和 10 個後續行。 若要繼續列出腳本,請按 ENTER 鍵。l <m>,List:顯示 16 行的腳本,開頭為<m>所指定的行號。l <m> <n>,List:顯示腳本的<n>行,從<m>指定的行號開始。q、Stop、Exit:停止執行腳本,並結束調試程式。 如果您要執行Debug-JobCmdlet 來偵錯作業,Exit命令會中斷調試程式,並允許作業繼續執行。k,Get-PsCallStack:顯示目前的呼叫堆棧。<Enter>:如果最後一個命令是 Step (s)、StepOver (v) 或 List (l),則重複最後一個命令。 否則,代表送出動作。?,h:顯示調試程式命令說明。
要退出除錯器,您可以使用 Stop (q)。
從 PowerShell 5.0 開始,您可以執行 Exit 命令,結束您執行 Debug-Job 或 Debug-Runspace啟動的巢狀偵錯會話。
通過使用這些調試器命令,您可以運行腳本、在關注點上停止、檢查變數的值和系統狀態,並繼續運行腳本,直到發現問題。
注意:如果單步執行帶有重定向運算元(如 “”)>的語句,則 PowerShell 調試器將單步執行腳本中所有剩餘的語句。
顯示文稿變數的值
當您在除錯程式中時,您也可以輸入命令、顯示變數的值、使用 Cmdlet,以及在命令行執行腳本。
您可以顯示正在除錯的文稿中所有變數的目前值,但以下自動變數除外:
$_
$Args
$Input
$MyInvocation
$PSBoundParameters
如果嘗試顯示這些變數中的任何一個的值,則會在調試器使用的內部管道中獲取該變數的值,而不是腳本中變數的值。
要顯示正在調試的腳本的這些變數的值,請在腳本中將 automatic 變數的值分配給新變數。 然後,您可以顯示新變數的值。
例如,
$scriptArgs = $Args
$scriptArgs
在本主題的範例中,變數的值 $MyInvocation 將按如下方式重新分配:
$scriptname = $MyInvocation.MyCommand.Path
調試器環境
當您到達斷點時,請輸入調試程序環境。 命令提示字元會變更,使其開頭為 “[DBG]:”。 如果要調試工作流,則提示符為 “[WFDBG]”。 您可以自訂提示。
如需自訂提示的詳細資訊,請參閱 about_Prompts。
此外,在某些主機應用程式(如 PowerShell 控制台)中(但在 Windows PowerShell 集成腳本環境 [ISE] 中不是),會打開一個嵌套提示進行調試。 您可以藉由在命令提示字元中出現的重複大於字元 (ASCII 62) 來偵測巢狀提示。
例如,以下是 PowerShell 控制台中的預設調試提示符:
[DBG]: PS (get-location)>>>
您可以使用自動變數 $NestedPromptLevel 來尋找巢狀層級。
此外,在局部範圍內定義了一個自動變數 $PSDebugContext。 您可以使用變數的存在 $PsDebugContext 來確定您是否在除錯器中。
例如:
if ($PSDebugContext) {"Debugging"} else {"Not Debugging"}
您可以在偵錯中使用 $PSDebugContext 變數的值。
[DBG]: PS>>> $PSDebugContext.InvocationInfo
Name CommandLineParameters UnboundArguments Location
---- --------------------- ---------------- --------
= {} {} C:\ps-test\vote.ps1 (1)
調試和範圍
進入除錯器不會更改您作的範圍,但當您到達腳本中的斷點時,您將進入腳本範圍。 腳本範圍是您執行調試程式之範圍的子系。
若要尋找腳本範圍中定義的變數和別名,請使用 Get-Alias 或 Get-Variable Cmdlet 的 Scope 參數。
例如,下列命令會取得本機 (script) 範圍中的變數:
Get-Variable -scope 0
您可以將命令縮寫為:
gv -s 0
這是只查看您在腳本中定義的變數,以及在偵錯時定義變數的實用方式。
在命令行中調試
當您設定變數斷點或命令斷點時,只能在腳本檔案中設定斷點。 不過,根據預設,斷點會在目前會話中執行的任何項目上設定。
例如,如果您在 $name 變數上設定斷點,調試程式會在您執行的任何腳本、命令、函式、函式、腳本 Cmdlet 或表達式中,中斷任何 $name 變數,直到停用或移除斷點為止。
這可讓您在更逼真的內容中偵錯腳本,這些腳本可能會受到會話和使用者配置檔中的函式、變數和其他腳本的影響。
行斷點特定於文稿檔,因此僅在腳本檔中設置它們。
偵錯工作流程
PowerShell 4.0 調試器可用於在PowerShell控制台或 Windows PowerShell ISE 中調試 PowerShell 工作流。 使用PowerShell調試程式來偵錯工作流程有一些限制。
- 您可以在調試器中查看工作流變數,但不支援從調試器中設置工作流變數。
- 在工作流調試器中停止時,Tab 鍵完成不可用。
- 工作流程偵錯僅適用於從PowerShell腳本同步執行的工作流程。 如果工作流作為作業運行(使用 AsJob 參數),則無法調試工作流。
- 其他嵌套調試方案(例如,調用其他工作流的工作流或調用腳本的工作流)未實現。
下列範例示範如何偵錯工作流程。 當調試器單步執行工作流函數時,調試器提示符將更改為“[WFDBG]”。
PS C:> Set-PSBreakpoint -Script C:\TestWFDemo1.ps1 -Line 8
ID Script Line Command Variable Action
-- ------ ---- ------- -------- ------
0 TestWFDemo1.ps1 8
PS C:> C:\TestWFDemo1.ps1
Entering debug mode. Use h or ? for help.
Hit Line breakpoint on 'C:\TestWFDemo1.ps1:8'
At C:\TestWFDemo1.ps1:8 char:5
+ Write-Output -InputObject "Now writing output:"
# +!INCLUDE[]~~~~~
[WFDBG:localhost]: PS C:>> list
# 3:
4: workflow SampleWorkflowTest
5: {
6: param ($MyOutput)
# 7:
8:* Write-Output -InputObject "Now writing output:"
9: Write-Output -Input $MyOutput
# 10:
11: Write-Output -InputObject "Get PowerShell process:"
12: Get-Process -Name powershell
# 13:
14: Write-Output -InputObject "Workflow function complete."
15: }
# 16:
17: # Call workflow function
18: SampleWorkflowTest -MyOutput "Hello"
[WFDBG:localhost]: PS C:>> $MyOutput
Hello
[WFDBG:localhost]: PS C:>> stepOver
Now writing output:
At C:\TestWFDemo1.ps1:9 char:5
+ Write-Output -Input $MyOutput
# +!INCLUDE[]~
[WFDBG:localhost]: PS C:>> list
4: workflow SampleWorkflowTest
5: {
6: param ($MyOutput)
# 7:
8: Write-Output -InputObject "Now writing output:"
9:* Write-Output -Input $MyOutput
# 10:
11: Write-Output -InputObject "Get PowerShell process:"
12: Get-Process -Name powershell
# 13:
14: Write-Output -InputObject "Workflow function complete."
15: }
# 16:
17: # Call workflow function
18: SampleWorkflowTest -MyOutput "Hello"
# 19:
[WFDBG:localhost]: PS C:>> stepOver
Hello
At C:\TestWFDemo1.ps1:11 char:5
+ Write-Output -InputObject "Get PowerShell process:"
# +!INCLUDE[]~~~~~~~~~
[WFDBG:localhost]: PS C:>> stepOut
Get PowerShell process:
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
433 35 106688 128392 726 2.67 7124 powershell
499 44 134244 172096 787 2.79 7452 powershell
Workflow function complete.
偵錯函式
當您在具有 Begin、Process和 End 區段的函式上設定斷點時,調試程式會在每個區段的第一行中斷。
例如:
function test-cmdlet {
begin {
write-output "Begin"
}
process {
write-output "Process"
}
end {
write-output "End"
}
}
C:\PS> Set-PSBreakpoint -command test-cmdlet
C:\PS> test-cmdlet
Begin
Entering debug mode. Use h or ? for help.
Hit Command breakpoint on 'prompt:test-cmdlet'
test-cmdlet
[DBG]: C:\PS> c
Process
Entering debug mode. Use h or ? for help.
Hit Command breakpoint on 'prompt:test-cmdlet'
test-cmdlet
[DBG]: C:\PS> c
End
Entering debug mode. Use h or ? for help.
Hit Command breakpoint on 'prompt:test-cmdlet'
test-cmdlet
# [DBG]: C:\PS>
調試遠端文本
從 PowerShell 5.0 開始,您可以在遠端會話中、控制台或 Windows PowerShell ISE 中運行 PowerShell 調試器。
Enter-PSSession 功能已更新,允許您重新連接並進入在遠端電腦上運行且當前正在運行腳本的已斷開連接的會話。 如果執行中的文稿叫用斷點,您的用戶端會話會自動啟動調試程式。
以下示例顯示了其工作原理,在腳本中的第 6、11、22 和 25 行設置了斷點。 請注意,在該示例中,當調試器啟動時,有兩個標識提示:運行會話的計算機的名稱,以及讓您知道處於調試模式的 DBG 提示。
Enter-Pssession -Cn localhost
[localhost]: PS C:\psscripts> Set-PSBreakpoint .\ttest19.ps1 6,11,22,25
ID Script Line Command Variable Action
-- ------ ---- ------- -------- ------
0 ttest19.ps1 6
1 ttest19.ps1 11
2 ttest19.ps1 22
3 ttest19.ps1 25
[localhost]: PS C:\psscripts> .\ttest19.ps1
Hit Line breakpoint on 'C:\psscripts\ttest19.ps1:11'
At C:\psscripts\ttest19.ps1:11 char:1
+ $winRMName = "WinRM"
# + ~
[localhost]: [DBG]: PS C:\psscripts>> list
6: 1..5 | foreach { sleep 1; Write-Output "hello2day $_" }
7: }
# 8:
9: $count = 10
10: $psName = "PowerShell"
11:* $winRMName = "WinRM"
12: $myVar = 102
# 13:
14: for ($i=0; $i -lt $count; $i++)
15: {
16: sleep 1
17: Write-Output "Loop iteration is: $i"
18: Write-Output "MyVar is $myVar"
# 19:
20: hello2day
# 21:
[localhost]: [DBG]: PS C:\psscripts>> stepover
At C:\psscripts\ttest19.ps1:12 char:1
+ $myVar = 102
# + ~
[localhost]: [DBG]: PS C:\psscripts>> quit
[localhost]: PS C:\psscripts> Exit-PSSession
PS C:\psscripts>
範例
此測試文本檢測作系統的版本並顯示適合系統的消息。 它包含函式、函數調用和變數。
下列命令會顯示測試文稿檔案的內容:
PS C:\PS-test> Get-Content test.ps1
function psversion {
"PowerShell " + $PSVersionTable.PSVersion
if ($PSVersionTable.PSVersion.Major -lt 6) {
"Upgrade to PowerShell 6.0!"
}
else {
"Have you run a background job today (start-job)?"
}
}
$scriptName = $MyInvocation.MyCommand.Path
psversion
"Done $scriptName."
若要開始,請在腳本感興趣的點設定斷點,例如行、命令、變數或函式。
從在目前目錄中 Test.ps1 腳本的第一行建立行斷點開始。
PS C:\ps-test> Set-PSBreakpoint -line 1 -script test.ps1
您可以將此指令縮寫為:
PS C:\ps-test> spb 1 -s test.ps1
該命令返回一個行斷點物件 (System.Management.Automation.LineBreakpoint)。
Column : 0
Line : 1
Action :
Enabled : True
HitCount : 0
Id : 0
Script : C:\ps-test\test.ps1
ScriptName : C:\ps-test\test.ps1
現在,啟動腳本。
PS C:\ps-test> .\test.ps1
當腳本到達第一個斷點時,斷點訊息會指出調試程式為作用中。 它會描述斷點,並預覽腳本的第一行,這是函式宣告。 命令提示字元也會變更,表示調試程式具有控制權。
預覽行包含文稿名稱和預覽命令的行號。
Entering debug mode. Use h or ? for help.
Hit Line breakpoint on 'C:\ps-test\test.ps1:1'
test.ps1:1 function psversion {
# DBG>
使用 Step 命令 (s) 來執行腳本中的第一個語句,並預覽下一個語句。 下一個語句會使用 $MyInvocation 自動變數,將 $scriptName 變數的值設定為腳本檔案的路徑和檔名。
DBG> s
test.ps1:11 $scriptName = $MyInvocation.MyCommand.Path
此時, $scriptName 不會填充變數,但您可以通過顯示變數的值來驗證變數的值。 此處的值為 $null。
DBG> $scriptname
# DBG>
使用另一個 Step 命令執行當前語句並預覽腳本中的下一個語句。 下一個語句調用 PsVersion 函數。
DBG> s
test.ps1:12 psversion
此時,會填入 $scriptName 變數,但您可以藉由顯示變數的值來驗證變數的值。 在此情況下,值會設定為腳本路徑。
DBG> $scriptName
C:\ps-test\test.ps1
使用另一個 Step 命令來執行函數調用。 按 ENTER 鍵,或輸入步驟的 “s”。
DBG> s
test.ps1:2 "PowerShell " + $PSVersionTable.PSVersion
偵錯訊息會在函式中包含語句的預覽。 若要執行此語句,並預覽函式中的下一個語句,您可以使用 Step 命令。 但在此情況下,請使用 StepOut 命令 (o)。 它會完成函式的執行(除非它到達斷點),並逐步執行腳本中的下一個語句。
DBG> o
Windows PowerShell 2.0
Have you run a background job today (start-job)?
test.ps1:13 "Done $scriptName"
由於我們位於腳本中的最後一個語句上,因此 Step、StepOut 和 Continue 命令具有相同的效果。 在此情況下,請使用 StepOut (o)。
Done C:\ps-test\test.ps1
PS C:\ps-test>
StepOut 命令會執行最後一個命令。 標準命令提示字元表示調試程式已結束,並將控制權傳回給命令處理器。
現在,請再次執行調試程式。 首先,若要刪除目前的斷點,請使用 Get-PSBreakpoint 和 Remove-PSBreakpoint Cmdlet。 (如果您認為您可能會重複使用斷點,請使用 Disable-PSBreakpoint Cmdlet,而不是 Remove-PSBreakpoint。
PS C:\ps-test> Get-PSBreakpoint| Remove-PSBreakpoint
您可以將此指令縮寫為:
PS C:\ps-test> gbp | rbp
或者,藉由撰寫函式來執行 命令,例如下列函式:
function delbr { gbp | rbp }
現在,在 $scriptname 變數上建立斷點。
PS C:\ps-test> Set-PSBreakpoint -variable scriptname -script test.ps1
您可以將命令縮寫為:
PS C:\ps-test> sbp -v scriptname -s test.ps1
現在,啟動腳本。 腳本會到達變數斷點。 默認模式為 Write,因此執行會在變更變數值的語句之前停止。
PS C:\ps-test> .\test.ps1
Hit Variable breakpoint on 'C:\ps-test\test.ps1:$scriptName'
(Write access)
test.ps1:11 $scriptName = $MyInvocation.MyCommand.Path
# DBG>
顯示 $scriptName 變數的目前值,$null。
DBG> $scriptName
# DBG>
使用 Step 命令執行填充變數的語句。
然後,顯示 $scriptName 變數的新值。
DBG> $scriptName
C:\ps-test\test.ps1
```powershell
Use a Step command (s) to preview the next statement in the script.
```powershell
DBG> s
test.ps1:12 psversion
下一個語句是對 PsVersion 函數的調用。 要跳過該函數但仍執行它,請使用 StepOver 命令 (v)。 如果您在使用 StepOver 時已經在函數中,則它無效。 將顯示函數調用,但不會執行該調用。
DBG> v
Windows PowerShell 2.0
Have you run a background job today (start-job)?
test.ps1:13 "Done $scriptName"
StepOver 命令執行該函數,並預覽腳本中的下一條語句,該語句將列印最後一行。
使用 Stop 命令 (t) 退出除錯器。 命令提示字元會還原為標準命令提示字元。
C:\ps-test>
若要刪除斷點,請使用 Get-PSBreakpoint 和 Remove-PSBreakpoint Cmdlet。
PS C:\ps-test> Get-PSBreakpoint| Remove-PSBreakpoint
在 PsVersion 函數上創建新的命令斷點。
PS C:\ps-test> Set-PSBreakpoint -command psversion -script test.ps1
您可以將此指令縮寫為:
PS C:\ps-test> sbp -c psversion -s test.ps1
現在,請執行腳本。
PS C:\ps-test> .\test.ps1
Hit Command breakpoint on 'C:\ps-test\test.ps1:psversion'
test.ps1:12 psversion
# DBG>
腳本會在函式呼叫到達斷點。 此時,該函數尚未被調用。 這可讓您使用 Set-PSBreakpoint 的 Action 參數來設定斷點執行的條件,或執行準備或診斷工作,例如啟動記錄或叫用診斷或安全性腳本。
若要設定動作,請使用 Continue 命令 (c) 結束腳本,並使用 Remove-PSBreakpoint 命令來刪除目前的斷點。 (斷點是唯讀的,因此無法向當前斷點添加作。
DBG> c
Windows PowerShell 2.0
Have you run a background job today (start-job)?
Done C:\ps-test\test.ps1
PS C:\ps-test> Get-PSBreakpoint| Remove-PSBreakpoint
PS C:\ps-test>
現在,使用動作建立新的命令斷點。 下列命令會設定命令斷點,其動作會在呼叫 函式時記錄 $scriptName 變數的值。 由於作中未使用 Break 關鍵字,因此執行不會停止。 (反引號 (') 是行繼續符。
PS C:\ps-test> Set-PSBreakpoint -command psversion -script test.ps1 `
-action { add-content "The value of `$scriptName is $scriptName." `
-path action.log}
您也可以新增設定斷點條件的動作。 在下列命令中,只有在執行原則設定為 RemoteSigned 時,才會執行命令斷點,這是仍然允許您執行腳本的最嚴格原則。 (反引號 (') 是延續字元。
PS C:\ps-test> Set-PSBreakpoint -script test.ps1 -command psversion `
-action { if ((Get-ExecutionPolicy) -eq "RemoteSigned") { break }}
作中的 Break 關鍵字指示調試器執行斷點。 您還可以使用 Continue 關鍵字指示除錯器在不中斷的情況下執行。 由於默認關鍵字是 Continue,因此必須指定 Break 才能停止執行。
現在,請執行腳本。
PS C:\ps-test> .\test.ps1
Hit Command breakpoint on 'C:\ps-test\test.ps1:psversion'
test.ps1:12 psversion
由於執行原則設定為 RemoteSigned,因此執行會在函數調用停止。
此時,您可能會想要檢查呼叫堆疊。
Get-PsCallStack使用 cmdlet 或 Get-PsCallStack debugger 命令 (k)。 下列命令會取得目前的呼叫堆疊。
DBG> k
2: prompt
1: .\test.ps1: $args=[]
0: prompt: $args=[]
此範例只示範幾個使用PowerShell調試程式的方法。
有關調試器 cmdlet 的詳細資訊,請鍵入以下命令:
help <cmdlet-name> -full
例如,輸入:
help Set-PSBreakpoint -full
PowerShell 中的其他偵錯功能
除了 PowerShell 調試程式之外,PowerShell 還包含數個可用來偵錯腳本和函式的其他功能。
Windows PowerShell ISE 包括一個互動式圖形調試器。 有關詳細資訊,請啟動 Windows PowerShell ISE 並按 F1。
Set-PSDebugCmdlet 提供非常基本的腳本偵錯功能,包括逐步執行和追蹤。Set-StrictMode使用 cmdlet 可檢測對未初始化變數的引用、對物件不存在的屬性的引用以及無效的函數語法。將診斷語句新增至腳本,例如顯示變數值的語句、從命令行讀取輸入的語句,或報告目前指令的語句。 使用包含這項工作之 Write 動詞的 Cmdlet,例如
Write-Host、Write-Debug、Write-Warning和Write-Verbose。