-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Description
I'm looking at bringing some of the functionality from the most popular modules I have written into native PowerShell when it is appropriate to do so.
Wait-Debugger and DebugPx's Enter-Debugger command were both built at the same time, independently of one another. I always expected the native Wait-Debugger command would supercede Enter-Debugger at some point, but the way it entered the debugger on the statement following the Wait-Debugger command prevented it from supporting certain functionality. That limitation was removed when PR #8205 was merged. The debugger now stops on the Wait-Debugger command itself rather than on the statement following that command. With that in place, now is a good time to catch it up so that it supercedes Enter-Debugger in PowerShell 7 and later releases.
Summary of the new feature/enhancement
As a script author
I want to use Wait-Debugger in a pipeline
So that I can attach a debugger in the location most appropriate for my needs.
As a script author
I want to use a conditional scriptblock in a Wait-Debugger call
So that I can conditionally attach a debugger to a script.
As a script author
I want to write a custom message to the host as I enter the debugger when a certain condition is met
So that I am reminded what happened when I attach a debugger to a script.
Proposed technical implementation details
This PR would add additional parameters to the Wait-Debugger command, and update that command for use in the pipeline. The parameters to consider adding include:
[-ConditionScript] <scriptblock>
[-Message <string>]
[-InputObject <PSObject>]
The code for these parameters is already in use in Enter-Debugger in DebugPx. It would simply be ported from that command in an appropriate way into Wait-Debugger, and hidden behind an experimental feature while people try it out.
Example 1: Using Wait-Debugger in a pipeline
This example demonstrates using Wait-Debugger in a pipeline, where the debugger will break automatically on each object as it passes through the pipeline.
Get-Process | Wait-Debugger | Stop-Process -WhatIfYou would most likely use Wait-Debugger in a pipeline with a condition, which you can see in the next example.
Example 2: Using Wait-Debugger with a condition script block
This example demonstrates using Wait-Debugger with a conditional script block. It will only wait for a debugger to attach if the condition has been met.
Wait-Debugger -ConditionScript {$x -eq $null}
Get-Process | Wait-Debugger {$_.Id -eq $PID} | Stop-Process -WhatIfThe first command will wait for a debugger to attach (or enter a breakpoint immediately if run locally), but only if $x -eq $null returns true.
The second command will wait for a debugger to attach (or enter a breakpoint immediately if run locally) if the current pipeline process ID is $PID. -ConditionScript is positional, allowing it to be used in the middle of a pipeline with great ease.
Example 3: Outputting a message in the host when a debugger is attached.
foreach ($value in $myCollection) {
Wait-Debugger {$value.Name -eq $null} -Message 'It happened! The name of a collection item is null!'
# Do more things with $value here
}Additional changes to consider:
Breakpoint alias
It would also be appropriate to add breakpoint as an alias for Wait-Debugger. Since Wait-Debugger is a command that you typically add temporarily to a script and then later remove it, and since the intent of that command is to trigger an on-demand breakpoint at that location, causing the debugger to wait for a remote debugger to attach, or entering the debugger immediately if the script is run locally, the breakpoint alias is appropriate to facilitate easier and more expressive use of this command. This alias is supported by DebugPx for Enter-Debugger already, and it makes it very convenient to work with the debugger.
There is an additional alias for Enter-Debugger in DebugPx: bp. While I love the simplicity of that alias, and while that alias gets heavy use by me personally (I don't have telemetry data from others at this time), I decided not to propose it be brought forward because we're cross platform and Linux has a bp command already. I don't want that conflict with existing commands.
Discoverability and the potential benefit in renaming Wait-Debugger as Enter-Breakpoint
There are some challenges with the Wait-Debugger name, as follows:
Wait-Debuggeris not a very discoverable command name, because it's the only command that ships with PowerShell with a noun ofDebugger.- It uses the verb
Wait, which met the original intent well because it would cause a remote script to wait for a debugger to attach to it, but it also works in local scripts, in which case there is no wait, and that makes it a little confusing. - Non-developers are much less familiar with the concept of attaching a debugger.
- From an end user's perspective, given the behavior in local and remote scripts, it seems like this command simply acts as a dynamic breakpoint that is declared in the script itself -- i.e. the command itself is a breakpoint. It seems less about waiting for and attaching a debugger -- that's what you do once you hit a breakpoint, but only with a remote script.
Similarly, Enter-Debugger shares a few of those challenges. I chose the verb Enter for Enter-Debugger because it felt more descriptive (it causes PowerShell to enter the debugger in the current location), but it also shares the discoverability issues since it is a "lone" Debugger command (although that makes two, there should only be one going forward).
With those thoughts in mind, I find myself wondering If the command would be better named as Enter-Breakpoint, with aliases of breakpoint and etbp (that isn't a Linux command, and it follows the recommended alias naming making it easy to use and remember). This would of course have a Wait-Debugger alias for backwards compatibility.
This may not seem necessary, but renaming the command could provide the following benefits:
- It groups the command with other like commands (the
Breakpointnoun commands), which is a significant benefit for discoverability. - It focuses a learner's attention on one concept: breakpoints.
- It describes what the command does from an end user's perspective.
- It doesn't confuse folks with the verb
Wait, because all breakpoints work the same way, and waiting only comes into play when a script is running remotely. When local, they trigger according to their definition/action. When remote, when they trigger you need to attach a debugger to the remote process usingDebug-Job,Debug-Runspace, etc.
You might ask yourself why you would ever use an Enter-Breakpoint command in a script when you can actually set breakpoints. The answer to that question is simple: it may be conceptually easier for folks to drop a breakpoint into a script as a command, especially if you want that break to be conditional, than it is to set up a breakpoint to stop in the right location under the right conditions using an IDE.