One of the most useful troubleshooting and debugging features of PowerShell is breakpoints. You can set breakpoints via different criteria, but the most common place you'd like to set a breakpoint is when a problem occurs: when throwing an exception.

Adam Bertram

Adam Bertram is a 20-year IT veteran, Microsoft MVP, blogger, and trainer. Adam is the founder of the e-learning tech screencast platform TechSnips. Catch up on Adam’s articles at adamtheautomator.com, or follow TechSnips on Twitter at @techsnips_io.

It's useful to pause code execution during a long-running script at the exact time it throws an exception. After pausing the script, you can then investigate interactively from the console to see various things at the time of the exception. These include what state the code was in, what values variables it held, what line the code was on, and so on. Even though PowerShell has a few different built-in triggers like variables and line numbers to issue a breakpoint, it doesn't have a built-in way to set a breakpoint automatically when an exception occurs.

An easy way to set breakpoints in PowerShell is to use the Set-PSBreakpoint command. You can use this command to set breakpoints for a number of actions like for creation of a variable and when the script hits a certain line in a script. Once it hits the trigger, it will then either just halt the execution, or you can optionally run some code at that time by using the Action parameter.

The Action parameter is where a lot of power comes in. This parameter allows you to specify "filters" to trigger on a variable name, for example, but also set some criteria that the variable matches. If it meets that criterion, the debugger can pause the script or, if not, it can just skip it.

There's no built-in way to set a breakpoint when throwing an exception, so we must reverse engineer things a bit. We first need to figure out which variable changes only when throwing an exception. Through some digging, I've found we can use the $stackTrace variable.

The $stackTrace automatic variable contains the code execution history and is always up to date. Every time a line executes, the $stackTrace variable changes. Lucky for us, throwing an exception updates the $stackTrace variable as well.

To set a breakpoint only upon throwing an exception (and this is still not perfect), we must add some filters via the Action parameter. We must check the value of $stackTrace to see if it matches the criteria for throwing an exception. So far, with the help of Kirk Munro, we've come up with a couple of different criteria to check in $stackTrace to see if the last action performed was a thrown exception.

Below is the script block you can pass to the Action parameter of Set-PSBreakpoint to see whether the last action was a thrown exception.

This script block checks to see if $stackTrace doesn't look like a normal code execution. If not, it must be an exception. In this case, it breaks the code so we can enter the debugger.

Once you've built the script block for the Action parameter, the rest is simply running Set-PSBreakpoint to start looking for the value of $stackTrace that meets the criteria defined in the Action script block. Since we're only looking for new code executions, we'll also use the ‑Mode Write option so we negate any false positives of times to read the $stackTrace variable.

Debug on an exception

Debug on an exception



This approach is not perfect. At times PowerShell will still enter the debugger and not throw an exception. If you're able to improve upon this, please let me know in a comment below. I'd be glad to make this more reliable!

Join the 4sysops PowerShell group!

Your question was not answered? Ask in the forum!

4+
Share
2 Comments
  1. Jeff Humphreys 5 months ago

    I've found that hidden exceptions that weren't bubbling up were now getting paused at, such as 

    and so I changed to

    and it stopped breaking there.  Also

    was setting [var] to $null since I hadn't SELECTed a [var] column, but no error was being raised even with latest Strict-Mode.

    But now it breaks on those, and I can fix them easily!  Thanks so much for this code!

    0

  2. David Figueroa 5 months ago

    Your [void] is going to potentially hide errors. I would suggest putting it into a Try/Catch so that you can find out what's really going on.  

    David F.   

    0

Leave a reply

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2020

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account