about_Debuggers

主题
    about_Debuggers

简短说明
    说明 Windows PowerShell 调试程序。


详细说明
    调试是在脚本运行过程中对其进行检查的过程,目的是识别和更正脚本指令中的错误。Windows 
    PowerShell 调试程序可帮助检查和识别脚本中的错误和低效率之处。
  

    注意:Windows PowerShell 调试程序无法远程运行。若要调试远程计算机上的脚本,请将该脚本复
    制到本地计算机。


    可使用 Windows PowerShell 调试程序的功能,在 Windows PowerShell 脚本、函数、命令或
    表达式运行过程中对它们进行检查。Windows PowerShell 调试程序包含一组 cmdlet,可用来设置
    断点、管理断点以及查看调用堆栈。
 

    Windows PowerShell 提供了几种用于调试脚本、函数和命令的方法。


    方法 1:Set-PsDebug cmdlet 提供了基本脚本调试功能,包括单步执行和跟踪。有关详细信息,
        请键入:"get-help set-psdebug"。


    方法 2:使用 Set-StrictMode cmdlet 来检测是否存在对未初始化变量的引用、对不存在的对象
            属性的引用以及无效的函数语法。


    方法 3:在脚本中添加诊断语句,如用于显示变量值的语句,用于读取命令行输入的语句,或用于报告
            当前指令的语句。可出于调试目的使用包含 Write 动词的 cmdlet,如 Write-Host、Write-
            Debug、Write-Warning 和 Write-Verbose。


    方法 4:使用 Windows PowerShell 调试程序来调试脚本。或者,使用调试程序来调试在命令提示
            符下键入的函数或脚本块。可以设置断点、单步执行脚本、检查变量的值、运行诊断和
        日志记录命令并显示调用堆栈。
    
  调试程序 Cmdlet
      Windows PowerShell 调试程序包含下面一组 cmdlet:


          Set-PsBreakpoint:     在行、变量和命令上设置断点。

          Get-PsBreakpoint:     获取当前会话中的断点。

          Disable-PsBreakpoint: 关闭当前会话中的断点。

          Enable-PsBreakpoint:  重新启用当前会话中的断点。

          Remove-PsBreakpoint:  删除当前会话中的断点。

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


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


      在到达断点时,执行会停止,调试程序将接管控制。


      若要停止调试程序,请运行脚本、命令或函数,直到运行完成。或者,键入“stop”或“t”。
  

  调试程序命令
      在 Windows PowerShell 控制台中使用调试程序时,可使用以下命令来控制执行。
    

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


    s, Step-into        执行下一条语句,然后停止。


    v, Step-over        执行下一条语句,但跳过函数和调用。将执行被跳过的语句,
                但不单步执行。


    o, Step-out         移出当前函数;如果嵌套则上移一级。如果位于 main 函数体
                中,则继续前进到末尾或下一个断点。将执行被跳过的语句,
                但不单步执行。


    c, Continue         继续运行,直到脚本完成或到达下一个断点。将执行被跳过的语
                句,但不单步执行。


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

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

        l <m> <n>, List     显示从 <m> 所指定的行号开始的 <n> 行脚本。                           

        q, Stop             停止执行脚本并退出调试程序。


        k, Get-PsCallStack  显示当前调用堆栈。


    <Enter>             如果最后一个命令是 Step (s)、Step-over (v) 或 List (l),
                则重复该命令。否则表示提交操作。
                           

    ?, h                显示调试程序命令帮助。


      若要退出调试程序,请使用 Stop (q)。


      您还可以在调试程序中输入命令、显示变量的值、使用 cmdlet 和运行脚本。


      通过使用这些调试程序命令,可以运行脚本、在相关点处停止、检查变量的值和
      系统的状态,以及继续运行脚本直到发现问题。


  调试程序环境
      在到达断点时,会进入调试程序环境中。此时命令提示符变为以“[DBG]:”开头。可以自定义提示符。

     
      另外,在某些主机应用程序如 Windows PowerShell 控制台中,将打开用于调试的嵌套提示符
      (但在 Windows PowerShell 集成脚本环境 [ISE] 中不是这样)。您可以通过命令提示符中重
      复的大于号字符 (ASCII 62) 看出提示符嵌套。


      例如,以下是 Windows 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 参数。


      例如,以下命令可获取本地(脚本)作用域中的变量:


      get-variable -scope 0


      可将该命令缩写为:


    gv -s 0


      在您只想查看在脚本中定义的变量以及在调试过程中定义的变量时,这是一个有用的方法。


  在命令行上进行调试
      在设置变量断点或命令断点时,可只在脚本文件中设置。但在默认情况下,
      该断点会设置在运行于当前会话中的所有内容。


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


      这可使您在更加真实的环境下对脚本进行调试,在这样的环境下,脚本可能会
      受到会话中和用户配置文件中的函数、变量以及其他脚本的影响。


      行断点是脚本文件所特有的,因此只能在脚本文件中设置。


  调试函数
      当在包含 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>


  调试远程脚本
      不能在远程会话中运行 Windows PowerShell 调试程序。若要调试远程
      计算机上的脚本,请将该脚本复制到本地计算机。


      以下命令将 Test.ps1 脚本从 Server01 远程计算机复制到本地计算机:


          invoke-command -computername Server01 `
          {get-content c:\ps-test\test.ps1} | set-location c:\ps-test\test.ps1


  示例
      此测试脚本检测操作系统的版本,并显示一条与系统相关的消息。
      脚本中包含一个函数、一个函数调用和一个变量。


      以下命令显示测试脚本文件的内容:

    
      c:>\PS-test> get-content test.ps1


      function psversion {
             "Windows Powershell " + $psversiontable.psversion
              if ($psversiontable.psversion.major -lt 2) {
                  "Upgrade to Windows PowerShell 2.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 命令 (s) 执行当前语句并预览脚本中的下一条语句。下一条语句将调用 
      PsVersion 函数。


      DBG> s
      test.ps1:12 psversion


      此时已填充 $ScriptName 变量,您可显示该变量的值以验证该值。在本例中,
      已将该值设置为脚本路径。


          DBG> $scriptname
          C:\ps-test\test.ps1
   

      使用另一个 Step 命令来执行函数调用。按 Enter 或键入"s"以执行 Step 命令。


      DBG> s
      test.ps1:2       "Windows Powershell " + $psversiontable.psversion


      调试消息中包含对函数中语句的预览。若要执行此语句并预览函数中的下一条语句,
      可使用一个 Step 命令。但本例中使用的是 Step-Out 命令 (o)。该命令将完成函
      数的执行(除非遇到断点)并步入脚本中的下一条语句。


      DBG> o
      Windows Powershell 2.0
      Have you run a background job today (start-job)?
      test.ps1:13 "Done $scriptname"


      由于已位于脚本中的最后一条语句上,因此 Step、Step-Out 和 Continue 命令的效果相同。
      本例中使用 Step-Out (o)。


      Done C:\ps-test\test.ps1
      PS C:\ps-test>


      Step-Out 命令将执行最后一条命令。显示的标准命令提示符表明调试程序已退出,
      控制权已返还给命令处理程序。


      现在,再次运行调试程序。首先,使用 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


      显示 $scriptname 变量的当前值,该值为 $null。


          DBG> $scriptname
          DBG>

      使用 Step 命令 (s) 执行用于填充该变量的语句。然后,显示 $scriptname 变量的新值。


      DBG> $scriptname
      C:\ps-test\test.ps1


      使用 Step 命令 (s) 预览脚本中的下一条语句。


      DBG> s
      test.ps1:12 psversion

   
      下一条语句是对 PsVersion 函数的调用。若要跳过函数但仍执行该函数,请使用 Step-Over 命
      令 (v)。如果使用 Step-Over 时当前位置已在函数中,则该函数调用将无效。这种情况下将显示函
      数调用,但不会执行该函数调用。

    
      DBG> v
      Windows Powershell 2.0
      Have you run a background job today (start-job)?
      test.ps1:13 "Done $scriptname"


      Step-Over 命令执行该函数,预显脚本中的下一条语句(该语句输出最后一行)。


      使用 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=[]


      此示例仅演示了使用 Windows PowerShell 调试程序的众多方法中的几种。


      有关调试程序 cmdlet 的详细信息,请键入以下命令:


          help <cmdlet-name> -full


      例如,键入:


          help set-psbreakpoint -full


另请参阅
    Disable-PsBreakpoint
    Get-PsBreakpoint  
    Remove-PsBreakpoint
    Set-PsBreakpoint 
    Set-PsDebug
    Set-Strictmode
    Write-Debug
    Write-Verbose  
    Enable-PsBreakpoint
    Get-PsCallStack