With PowerShell v2, a new and much improved command line debugger was introduced. The old one is still around though. Anyway, more information can be found in the help subject about_Debuggers.
The strange part is that Set-PsDebug –Step invokes the old debugger and there does not seem to be a way of invoking the new one. You can only invoke the new one by setting a breakpoint. Even though, breakpoints are a very useful feature which I use a lot, I would also like to do it from inside a script.
I have played around with some ways of doing this.
First, a self-contained function
Function Invoke-Debugger{
function debug{}
$bp=Set-PSBreakPoint -Command debug
debug
$bp | Remove-PSBreakpoint
}
function test{
write-host 1
Invoke-Debugger
write-host 2
}
test
It works great, but has the downside, that the current execution pointer is inside the Invoke-Debugger function -
1
Entering debug mode. Use h or ? for help.
Hit Command breakpoint on 'debug'
x.ps1:4 debug
7 $docs>>> l
1: Function Invoke-Debugger{
2: function debug{}
3: $bp=Set-PSBreakPoint -Command debug
4:* debug
5: $bp | Remove-PSBreakpoint
6: }
7:
8: function test{
9: write-host 1
10: Invoke-Debugger
11: write-host 2
12: }
13:
14: test
No matter how I try to tweak it, I end up in the same way.
Next, lets try using a two part approach (setting the breakpoint and doing some action to invoke it) -
$null=Set-PSBreakpoint -Variable InvokeDebugger
function test{
write-host 1
$InvokeDebugger=1
write-host 2
}
test
This is much better, now the execution pointer is right in the code -
1
Hit Variable breakpoint on '$InvokeDebugger' (Write access)
x.ps1:5 $InvokeDebugger=1
9 $docs>>> l
1: $null=Set-PSBreakpoint -Variable InvokeDebugger
2:
3: function test{
4: write-host 1
5:* $InvokeDebugger=1
6: write-host 2
7: }
8:
9: test
10:
Eventually, this led me to this piece of code. It is easier to write than the variable assignment and you can also define an easy-writeable alias for it -
function Invoke-Debugger{}
New-Alias id Invoke-Debugger
$null=Set-PSBreakPoint –Command Invoke-Debugger
function test{
write-host 1
id
write-host 2
}
test
The execution pointer is right at the call. If you include any statements in Invoke-Debugger, this will not work as well while ‘step’ will take execution into the function -
1
Hit Command breakpoint on 'Invoke-Debugger'
x.ps1:9 id
13 $docs>>> l
4: New-Alias id Invoke-Debugger
5: $null=Set-PSBreakPoint –Command Invoke-Debugger
6:
7: function test{
8: write-host 1
9:* id
10: write-host 2
11: }
12:
13: test
14:
This method also enables you to make conditional break using straight, normal code (compared to making the logic in the –action argument of Set-PSBreakPoint) -
filter test{
write-host "got $_"
if ($_ -eq 3) {id}
}
1..5 | test
and the output -
got 1
got 2
got 3
Hit Command breakpoint on 'Invoke-Debugger'
x.ps1:9 if ($_ -eq 3) {id}
14 $docs>>> l
4: New-Alias id Invoke-Debugger
5: $null=Set-PSBreakPoint –Command Invoke-Debugger
6:
7: filter test{
8: write-host "got $_"
9:* if ($_ -eq 3) {id}
10: }
11:
12: 1..5 | test
13:
You can include the Invoke-Debugger function and the Set-PSBreakPoint in your profile, so they are available in all our scripts.
Happy debugging..