about_Debuggers
簡短描述
描述 PowerShell 調試程式。
詳細描述
偵錯是在腳本執行時檢查腳本的程式,以識別並更正腳本指示中的錯誤。 PowerShell 調試程式可協助您檢查和識別腳本、函式、命令、PowerShell Desired 狀態設定 (DSC) 組態或表達式中的錯誤和效率。
從 PowerShell 5.0 開始,PowerShell 調試程式已更新為偵錯遠端電腦上的控制台或 Windows PowerShell 整合式腳本環境 (ISE) 中執行的腳本、函式、命令、組態或表達式。
注意
Windows PowerShell ISE 僅支援 Windows PowerShell。 針對 PowerShell 6 和更新版本,您必須搭配 PowerShell 的擴充功能使用 Visual Studio Code。 如需詳細資訊,請參閱 使用Visual Studio Code進行偵錯。
調試程式 Cmdlet
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
:顯示從 所<m>
指定的行號開始的 16 行腳本。l <m> <n>
,List
:顯示<n>
腳本行,開頭為 所<m>
指定的行號。q
、 、Stop
Exit
停止執行文稿,並結束除錯程式。 如果您要藉由執行Debug-Job
Cmdlet 來偵錯作業,Exit
命令會中斷調試程式,並允許作業繼續執行。k
,Get-PsCallStack
:顯示目前的呼叫堆疊。<Enter>
:如果Step
為 (s
)、(v
)StepOver
或List
(l
),則重複最後一個命令。 否則,代表送出動作。?
,h
:顯示調試程式命令說明。
若要結束調試程式,您可以使用 Stop
(q
)。
從 PowerShell 5.0 開始,您可以執行 Exit 命令來結束您執行 Debug-Job
或 Debug-Runspace
所啟動的巢狀偵錯會話。
使用這些調試程式命令,您可以執行腳本、停止關注點、檢查變數的值和系統的狀態,並繼續執行腳本,直到您發現問題為止。
注意
如果您使用重新導向運算元逐步執行 語句,例如 >
,PowerShell 調試程式會逐步執行腳本中所有剩餘語句。
顯示文稿變數的值
當您在除錯程式中時,您也可以輸入命令、顯示變數的值、使用 Cmdlet,以及在命令行執行腳本。 您可以在正在偵錯的文稿中顯示所有變數的目前值,但下列自動變數除外:
$_
$Args
$Input
$MyInvocation
$PSBoundParameters
當您顯示任何這些變數的值時,您會取得調試程式所使用之內部管線的變數值,而不是腳本中的變數值。
若要針對要偵錯的腳本顯示這些變數的值,請將幾行新增至您的腳本,將這些值儲存至新的變數。 在這些新行之後設定斷點。 然後,您可以顯示新變數的值。
例如,
$scriptArgs = $Args
$scriptname = $MyInvocation.PSCommandPath
調試程序環境
當您到達斷點時,請輸入調試程序環境。 命令提示字元會變更,使其開頭為 “[DBG]:”。 此外,在某些主機應用程式中,例如 PowerShell 控制台,會開啟巢狀提示以進行偵錯。 您可以藉由在命令提示字元中出現的重複大於字元 (ASCII 62) 來偵測巢狀提示。
如需自定義提示的詳細資訊,請參閱 about_Prompts。
您可以使用自動變數來尋找巢狀層級 $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-Variable
Cmdlet 的 Get-Alias
Scope 參數。
例如,下列命令會取得本機 (script) 範圍中的變數:
Get-Variable -scope 0
這是只查看您在腳本中定義的變數,以及在偵錯時定義變數的實用方式。
在命令行進行偵錯
當您設定變數斷點或命令斷點時,只能在腳本檔案中設定斷點。 不過,根據預設,斷點會在目前會話中執行的任何項目上設定。
例如,如果您在變數上 $name
設定斷點,調試程式會在執行的任何 $name
腳本、命令、函式、腳本 Cmdlet 或表示式中的任何變數上中斷,直到您停用或移除斷點為止。
這可讓您在更逼真的內容中偵錯腳本,這些腳本可能會受到會話和使用者配置檔中的函式、變數和其他腳本的影響。
行斷點專屬於腳本檔案,因此只會在腳本檔案中設定。
偵錯工作流程
調試程式可用來在PowerShell控制台或 Windows PowerShell ISE 中偵錯 PowerShell 工作流程。 使用PowerShell調試程式來偵錯工作流程有一些限制。
- 您可以在調試程式中檢視工作流程變數,但不支援從調試程式內設定工作流程變數。
- 在工作流程調試程式中停止時,索引標籤自動完成無法使用。
- 工作流程偵錯僅適用於從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:"
# ~~~~~
[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>
偵錯遠端文本
您可以執行 Enter-PSSession
來啟動互動式遠端 PowerShell 工作階段,您可以在其中設定斷點,並在遠端電腦上偵錯腳本檔案和命令。 Enter-PSSession
可讓您重新連接在遠端電腦上執行腳本或命令的已中斷聯機會話。 如果執行中的文稿叫用斷點,您的用戶端會話會自動啟動調試程式。 如果執行文本的已中斷聯機會話已叫用斷點,當您重新連線到會話時, 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>
範例
此測試腳本會偵測 PowerShell 版本,並顯示適當的版本訊息。 它包含函式、函數調用和變數。
下列命令會顯示測試文稿檔案的內容:
PS C:\PS-test> Get-Content test.ps1
function psversion {
"PowerShell " + $PSVersionTable.PSVersion
if ($PSVersionTable.PSVersion.Major -lt 7) {
"Upgrade to PowerShell 7!"
}
else {
"Have you run a background job today (start-job)?"
}
}
$scriptName = $MyInvocation.PSCommandPath
psversion
"Done $scriptName."
若要開始,請在腳本感興趣的點設定斷點,例如行、命令、變數或函式。
從在目前目錄中Test.ps1腳本的第一行建立行斷點開始。
PS C:\ps-test> Set-PSBreakpoint -line 1 -script 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.PSCommandPath
此時, $scriptName
不會填入變數,但您可以藉由顯示變數的值來驗證變數的值。 此處的值為 $null
。
DBG> $scriptname
DBG>
使用另一個 Step
命令 (s
) 來執行目前的語句,並在腳本中預覽下一個語句。 下一個語句會呼叫 函 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.PSCommandPath
DBG>
顯示變數的 $scriptName
目前值,也就是 $null
。
DBG> $scriptName
DBG>
Step
使用命令 (s
) 來執行填入變數的語句。 然後,顯示變數的新值 $scriptName
。
DBG> $scriptName
C:\ps-test\test.ps1
使用步驟命令 (s) 預覽文稿中的下一個語句。
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
調試程式命令 (k
)。 下列命令會取得目前的呼叫堆疊。
DBG> k
2: prompt
1: .\test.ps1: $args=[]
0: prompt: $args=[]
此範例只示範幾個使用PowerShell調試程式的方法。
PowerShell 中的其他偵錯功能
除了 PowerShell 調試程式之外,PowerShell 還包含數個可用來偵錯腳本和函式的其他功能。
Cmdlet
Set-PSDebug
提供非常基本的腳本偵錯功能,包括逐步執行和追蹤。Set-StrictMode
使用 Cmdlet 來偵測未初始化變數的參考、參考物件不存在的屬性,以及函式語法無效。將診斷語句新增至腳本,例如顯示變數值的語句、從命令行讀取輸入的語句,或報告目前指令的語句。 使用包含此工作的 Write 動詞指令的 Cmdlet,例如
Write-Host
、Write-Debug
、Write-Warning
和Write-Verbose
。