Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

debugging - Is there a way to enter the debugger on an error?

Is there a way to enter the PowerShell debugger in response to an error? The ErrorAction parameter has several values but I don't see anything like Debug. What I would like is to open the debugger like it would open if I had set a breakpoint, but only when an error occurs (from, say, Write-Error).

Edit I should clarify a bit: I am primarily a C# developer and somewhat new to PowerShell, what I am expecting is behavior similar to what the Visual Studio debugger gives you for "unhandled exceptions". It appears that it is more common for PowerShell commands to throw exceptions, while custom scripts seem to mostly use Write-Error. I don't think I particularly care to distinguish between the two, but I would like to handle both.

Trevor Sullivan's answer below mentions that you can use Set-PSBreakpoint -Command Write-Error -Action { break; }; which appears to work well to catch those cases. Though, I am finding that in many cases it is actually a command throwing an exception that I would like to break on. Roman Kuzmin's answer appears to work if you set $ErrorActionPreference = "stop", however, I have the problem that I cannot step through the program, it seems to break out of that location and end the script. If $ErrorActionPreference = "continue" it does not work for me. Traps in general seem to have a similar issue that they break out out of any nested scopes, which is not desired.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Of course. You can create conditional breakpoints in PowerShell, using the Set-PSBreakpoint cmdlet. Consider the following code. Save it as a script file, and execute it. There are in-line comments to help you understand what's going on.

Keep in mind that there are three different types of breakpoints:

  • Line
  • Variable
  • Command

Command Breakpoint

This code example is using the command breakpoint type, because I am telling it to only set breakpoints on Get-WmiObject commands. You can alternately specify a specific line number or a variable breakpoint type. You use the -Action parameter to specify the conditions under which you want the breakpoint to be set. You must use the break keyword somewhere inside the -Action ScriptBlock in order to instruct the debugger to pause execution of the PowerShell script.

# 1. Reset $Error to $null
$WmiError = $null;

# 2. Clean up any existing breakpoints
Get-PSBreakpoint | Remove-PSBreakpoint;

# 3. Set breakpoint, but only on Get-WmiObject commands, when the $WmiError variable is not $null
Set-PSBreakpoint -Command Get-WmiObject -Action { if ($WmiError) { break; } };

# 4. Failed Get-WmiObject command
Get-WmiObject -Class Win32_NonExistentClass -ErrorVariable WmiError;

# 5. Successful Get-WmiObject command
#    PowerShell breaks here, because:
#     - It's a Get-WmiObject command
#     - The $WmiError variable is not null
Get-WmiObject -Class Win32_BIOS;

Since you mentioned using Write-Error, you could set a PSBreakpoint on lines where Write-Error appears. Here is an example of how to do that:

Set-PSBreakpoint -Command Write-Error -Action { break; };

Pretty easy, right?

Variable Breakpoint

This example uses the variable PSBreakpoint type, but only when the variable's contents are modified. You can use the -Mode parameter to determine under what conditions the variable breakpoint is hit:

  • Read
  • ReadWrite
  • Write

Code:

# 1. Clean up any existing breakpoints
Get-PSBreakpoint | Remove-PSBreakpoint;

# 2. Set a PSBreakpoint of type "variable" on a variable named "Data," but only when it has changed
Set-PSBreakpoint -Action { Write-Host -ForegroundColor Green -Object ('The $Data variable has changed! Value is: {0}' -f $Data); break; } -Variable Data -Mode Write;

# 3. No break on this line, because we are not changing the variable
Write-Host -Object $Data;

# 4. Execution is paused on this line, because we change the variable
$Data = 1;

Line Breakpoint

Now that we've looked at the variable and command PSBreakpoint types, the last type of breakpoint to explore is the line breakpoint. If you were to copy/paste the code below, save it, and execute it, you would see that the code breaks on the Write-Host line (which happens to be line 9), but only when the Name property of the $Service variable is equal to WinRM. That is what the conditional statement in the -Action parameter's ScriptBlock defines.

# 1. Clean up any existing breakpoints
Get-PSBreakpoint | Remove-PSBreakpoint;

# 2. Set a PSBreakpoint of type "line" on line #8, but only if the $Service variable's Name property equals 'winrm'
Set-PSBreakpoint -Action { if ($Service.Name -eq 'winrm') { break; } } -Line 9 -Script $MyInvocation.MyCommand.Path;

# 3. Get a list of Windows Services and iterate over them
foreach ($Service in (Get-WmiObject -Class Win32_Service)) {
    Write-Host -Object ('Service name is: {0}' -f $Service.Name);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...