Debugging the PowerShell Debugger
When doing development for PowerShell cmdlets in a managed language such as C#, it can often be convenient to use the PowerShell ISE to test functionality. Since it has a built-in script debugger, it help with finding some errors. However, if you need to dig deeper into your own code and how it’s interacting with PowerShell, you want to debug the PowerShell debugger. Here’s how to do it:
- Attach WinDbg or your other favorite dbghelp based debugger to the PowerShell_ISE.exe instance that you’ll be using.
- Go ahead and load the SOS extension.
- Execute !DumpDomain in order to see the AppDomains and, more importantly for our purposes, the assemblies loaded in each.
- Find the System.Management.Automation.dll assembly which should look like the below.
Assembly: 000000c8c1a8e2a0 [C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll]
ClassLoader: 000000c8c1a84060
SecurityDescriptor: 000000c8c1a9d900
Module Name: 00007ffeb93f1000 C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll - Note its module address; use that address in the command !DumpModule /d -mt addr.
- You’ll see many classes with the text “debugger” in them. Depending on what you’re wanting to catch, you may want to choose something else like the RemoteDebugger. For this example, let’s use System.Management.Automation.ScriptDebugger. You’ll want to click on the DML for its method table to output some information about it.
- Take the command that the DML executed, !DumpMT /d addr, and add -MD so that it looks like !DumpMT /d -MD addr.
- Execute the newly formatted command. This will output all of the methods defined for the class as well as the method description address for each. We can use that address to set up breakpoints in WinDbg. You’ll notice that there are specified functions named for handling commands, jobs, etc defined for the ScriptDebugger class.
- For each method on which a breakpoint is desired, execute the command !bpmd -md addr. Go ahead and set a breakpoint on the method ProcessCommand.
- Let the application resume execution.
- Create a script such as $processes = Get-Process.
- Set a breakpoint on that line.
- Run the script.
You’ll notice that a breakpoint has been triggered on the ProcessCommand method. You can now use commands such as !ClrStack to view the managed stack, !DumpStack to see the entire stack, or !DumpStackObjects to see the objects on the stack.
Congratulations, you’re now debugging the PowerShell debugger!
Follow us on Twitter, https://www.twitter.com/WindowsSDK.