about_Debuggers

简短说明

介绍 PowerShell 调试器。

长说明

调试是在脚本运行时检查脚本以识别和更正脚本说明中的错误的过程。 PowerShell 调试器可帮助你检查和识别脚本、函数、命令、PowerShell Desired State Configuration (DSC) 配置或表达式中的错误和低效问题。

从 PowerShell 5.0 开始,PowerShell 调试器已更新为调试远程计算机上在控制台或Windows PowerShell集成脚本环境 (ISE) 运行的脚本、函数、命令、配置或表达式。

注意

Windows PowerShell ISE 仅支持Windows PowerShell。 对于 PowerShell 6 及更高版本,必须将 Visual Studio Code与 PowerShell 的扩展配合使用。 有关详细信息,请参阅使用 Visual Studio Code 进行调试

调试器 cmdlet

PowerShell 调试器包含以下一组 cmdlet:

  • Set-PSBreakpoint:设置行、变量和命令上的断点。
  • Get-PSBreakpoint:获取当前会话中的断点。
  • Disable-PSBreakpoint:关闭当前会话中的断点。
  • Enable-PSBreakpoint:重新启用当前会话中的断点。
  • Remove-PSBreakpoint:从当前会话中删除断点。
  • Get-PSCallStack:显示当前调用堆栈。

启动和停止调试器

若要启动调试器,请设置一个或多个断点,然后运行要调试的脚本、命令或函数。

到达断点时,执行将停止,并将控制权移交给调试器。

若要停止调试器,请运行脚本、命令或函数,直到它完成。 或者,键入 stopt

调试器命令

在 PowerShell 控制台中使用调试器时,请使用以下命令来控制执行。 在Windows PowerShell ISE 中,使用“调试”菜单上的命令。

注意

有关如何在其他主机应用程序中使用调试器的信息,请参阅主机应用程序文档。

  • sStepInto:执行下一个语句,然后停止。

  • vStepOver:执行下一个语句,但跳过函数和调用。 将执行跳过的语句,但不会单步遍历。

  • Ctrl+Break: (在 ISE 中全部中断) 中断 PowerShell 控制台或Windows PowerShell ISE 中的正在运行的脚本。 请注意,ctrl+Break in Windows PowerShell 2.0、3.0 和 4.0 关闭程序。 “全部中断”适用于本地和远程交互运行的脚本。

  • oStepOut:逐步退出当前函数;如果嵌套,则向上一个级别。 如果在main正文中,则它继续到末尾或下一个断点。 将执行跳过的语句,但不会单步遍历。

  • cContinue:继续运行,直到脚本完成或到达下一个断点。 将执行跳过的语句,但不会单步遍历。

  • lList:显示正在执行的脚本部分。 默认情况下,它显示当前行、前 5 行和 10 个后续行。 若要继续列出脚本,请按 Enter。

  • l <m>List:显示 16 行的脚本,从 指定的 <m>行号开始。

  • l <m> <n>List:显示 <n> 脚本的行,以 指定的 <m>行号开头。

  • qStopExit:停止执行脚本并退出调试器。 如果通过运行 Debug-Job cmdlet 调试作业,该 Exit 命令将分离调试器,并允许该作业继续运行。

  • kGet-PsCallStack:显示当前调用堆栈。

  • <Enter>:如果 Step () 、 StepOver (sv) 或 Listl () ,则重复上一个命令。 否则, 表示提交操作。

  • ?h:显示调试器命令“帮助”。

若要退出调试器,可以使用 Stop (q) 。

从 PowerShell 5.0 开始,可以运行 Exit 命令退出通过运行 Debug-JobDebug-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 参数。

例如,以下命令获取本地 (脚本) 范围内的变量:

Get-Variable -scope 0

这是一种有用的方法,用于仅查看在脚本中定义的变量,以及调试时定义的变量。

在命令行进行调试

设置变量断点或命令断点时,只能在脚本文件中设置断点。 但是,默认情况下,将在当前会话中运行的任何内容上设置断点。

例如,如果在变量上 $name 设置断点,调试器将中断运行的任何 $name 脚本、命令、函数、脚本 cmdlet 或表达式中的任何变量,直到禁用或删除断点。

这样,就可以在更现实的上下文中调试脚本,这些脚本可能会受到会话和用户配置文件中的函数、变量和其他脚本的影响。

行断点特定于脚本文件,因此仅在脚本文件中设置。

调试函数

在具有 beginprocessend 节的函数上设置断点时,调试器将在每个节的第一行中断。

例如:

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>

使用步骤命令 () 执行脚本中的第一个语句并预览下一个语句。 下一个语句使用 $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-PsBreakpointRemove-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

使用步骤命令 () 预览脚本中的下一个语句。

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-PsBreakpointRemove-PsBreakpoint cmdlet。

PS C:\ps-test> Get-PSBreakpoint| Remove-PSBreakpoint

Create函数上的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>

现在,使用 操作创建新的命令断点。 以下命令设置一个命令断点,其中包含一个操作,该操作在调用函数时记录变量的值 $scriptNamebreak 由于操作中未使用关键字 (keyword) ,因此不会停止执行。 反引号 (`) 是行继续符。

PS C:\ps-test> Set-PSBreakpoint -command psversion -script test.ps1  `
-action { add-content "The value of `$scriptName is $scriptName." `
-path action.log}

还可以添加为断点设置条件的操作。 在以下命令中,仅当执行策略设置为 RemoteSigned 时,才执行命令断点,RemoteSigned 是仍允许运行脚本的最严格策略。

PS C:\ps-test> Set-PSBreakpoint -script test.ps1 -command psversion `
-action { if ((Get-ExecutionPolicy) -eq "RemoteSigned") { break }}

操作break中的关键字 (keyword) 指示调试器执行断点。 还可以使用 continue 关键字 (keyword) 指示调试器在不中断的情况下执行。 由于默认关键字 (keyword) 为 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-HostWrite-DebugWrite-WarningWrite-Verbose

另请参阅