[PowerShell Script] PowerDbg v5.2—Using PowerShell to Control WinDbg
This version has two improvements and some scripts were changed to be compatible with this new version:
- Starting on version 5.2 the log used to save the command output, enabling the communication between PowerShell and WinDbg is not used anymore. Now all communication uses memory so it’s faster than before.
Note: the file POWERDBG-PARSED.LOG continues to exist since it’s useful for troubleshooting purposes and can be used as input for Excel or LogParser.
- Installation is easier now. Just one file has everything.
I’ve created a simple PowerDbg script that gives ASPX information. It’s going to be blogged after this article and should be used as reference.
Note: It was difficult for me to find some free time and work on PowerDbg. I tested it using all scripts (modified two of them) and using different dumps. However, it may have bugs. If you hunt a bug let me know, please!
DOWNLOAD POWERDBG
POWERDBG FILES
WinDbg.PSM1 ß Starting with this version this is the only file.
INSTALLATION
WinDbg.PSM1
Goes to %\WindowsPowerShell\Modules\WinDbg
Note: PowerDbg assumes the folder c:\debuggers as the default installation folder. This is true for the default installation of our private debugger version (Microsoft) but not for the public version, so, please, change this variable to reflect your installation:
param($cdbPath = "C:\debuggers\cdb.exe")
In order to know the exact location, use this command from PowerShell:
$profile
REQUIREMENT
PowerShell v2.0
USAGE
First, make sure you can run scripts:
set-executionpolicy remotesigned
From the WinDbg window type:
.server tcp:port=10456,server= ServerName ß ServerName is your server name.
The command above enables a port communication with the WinDbg instance as the server. You can use other port numbers.
From the PowerShell window you must initialize the communication:
Import-module WinDbg ß Imports our module WinDbg.PSM1
Connect-Windbg "tcp:Port=10456,Server=SERVER" ß Connects session to WinDbg instance.
Or:
Connect-Dbg "tcp:Port=10456,Server=SERVER" ß Connects session to WinDbg
Note: Don’t forget to load symbols and your extensions!
At this point you’re ready to use PowerDbg or PowerDbg scripts.
Example:
Analyze-PowerDbgThreads ß Cmdlet.
.\PowerDbgScriptExceptions ß Script.
Example 2:
Send-PowerDbgCommand "~* kpn 1000"
Parse-PowerDbgK
$ht = @{}
$ht = Convert-PowerDbgCSVToHashTable
Let's display the stack for thread 0:
# Replace the internal frame delimiter by new line and displays the stack.
write-host $ht["0"].Replace($global:g_frameDelimiter, "`n")
Example 3:
Send-PowerDbgCommand "!DumpObj 027a4c3c"
Parse-PowerDbgDUMPOBJ
$ht = Convert-PowerDbgCSVToHashTable
$ht["Name:"] <-- Displays the content of the field Name:
$ht["MethodTable:"] <-- Displays the content of the field MethodTable:
NEW FOR POWERDBG v5.2
PowerDbg now uses just one file that has the content of the previous two files and is not the Profile file anymore.
Easier to install and maintain.
The information from WinDbg to PowerDbg used a text file, now it’s all memory based.
It’s faster now than before and eliminates timing issues that used to happen when the file was being saved and the next PowerDbg command executed.
As a collateral benefit you don’t need to use Start-Sleep in your scripts anymore to avoid timing issues.
Note: The CSV file POWERDBG-PARSED.LOG is still used. It facilitates the troubleshooting and can be used as input for Excel or LogParser.
NEW FOR POWERDBG v5.1
Load-PowerDbgSymbols <$symbolPath>
Load symbols.
Usage:
Load-PowerDbgSymbols “SRV*c:\PUBLICSYMBOLS*https://msdl.microsoft.com/download/symbols"
Parse-PowerDbgASPXPAGES
Maps the output from the !ASPXPages command and saves it into the CSV file POWERDBG-PARSED.LOG
To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.
For this version the fields being considered are:
Key: HttpContext
Value: Timeout+Completed+Running+ThreadId+ReturnCode+Verb+RequestPath+QueryString
Parse-PowerDbgCLRSTACK
Maps the output from the !clrstack command or ~* e !clrstack and saves it into the CSV file POWERDBG-PARSED.LOG
To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.
Attention! The key is the thread number, and the value is the call stack separated by $global:g_frameDelimiter.
Commas " , " are replaced for " ; " to avoid confusion with the comma used by the CSV file.
If you use this cmdlet to parse the output from ~* e !clrstack, the threads not running managed code are automatically ignored.
Parse-PowerDbgTHREADS
Maps the output from the !threads command and saves it into the CSV file POWERDBG-PARSED.LOG
To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.
The following fields are extracted:
Thread Number - Key
ID+OSID+ThreadOBJ+State+GC+Context+Domain+Count+APT+Exception - Value
Parse-PowerDbgDSO
Maps the output from the !dso or ~* e !dso command and saves it into the CSV file POWERDBG-PARSED.LOG
To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.
The Thread Number is the key, and the stack is the value, like the way that Parse-PowerDbgK or Parse-PowerDbgCLRSTACK operates.
Attention! Commas are replaced by " ; " and $global:g_FrameDelimiter is used to separate frames.
CMDLETS FROM POWERDBG
Send-PowerDbgCommand <$command>
This was the most complex cmdlet, but now it’s just a wrapper for Invoke-WinDbgCommand.
SendPowerDbgCommand sends commands to WinDbg.
Parse-PowerDbgDT [$useFieldNames ]
Parses the output from the dt command and saves it into POWERDBG-PARSED.LOG using a CSV file format.
If $useFieldNames has a value, the cmdlet stores fields from struct/classes and values. Otherwise it stores offsets and values.
To convert the CSV file to a Hash Table use Convert-PowerDbgCSVToHashTable.
Convert-PowerDbgCSVToHashTable
Converts the output from the Parse-PowerDbg* cmdlets to a Hash Table.
Send-PowerDbgDML <$hyperLinkDML> <$commandDML>
Creates a DML command and sends it to WinDbg.
DML stands for Debug Markup Language. Using DML you can create hyperlinks that execute commands.
Parse-PowerDbgNAME2EE
Maps the output from the !name2ee and saves it into the CSV file POWERDBG-PARSED.LOG
Convert-PowerDbgCSVtoHashTable converts the output into a Hash Table.
Parse-PowerDbgDUMPMD
Maps the output from !dumpmd command and saves it into the CSV file POWERDBG-PARSED.LOG.
Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.
Parse-PowerDbgDUMPMODULE
Maps the output from !DumpModule command and saves it into the CSV file POWERDBG-PARSED.LOG
Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.
Parse-PowerDbgDUMPLMI
Maps the output from !lmi command and saves it into the CSV file POWERDBG-PARSED.LOG
Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.
Has-PowerDbgCOMMANDSUCCEEDED
Returns $true if the last command succeeded or $false if not.
Send-PowerDbgComment
Sends a comment, a string in bold, to the WinDbg window.
Parse-PowerDbgVERTARGET
Maps the output from vertarget command, either the Kernel Time or the User Time.
The output is saved into the CSV file POWERDBG-PARSED.LOG.
Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.
Parse-PowerDbgRUNAWAY
Maps the output of !runaway 1 or !runaway 2 and stores the results into the CSV file POWERDBG-PARSED.LOG
Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.
Attention! If you need to know the top threads consuming CPU time, use Convert-PowerDbgRUNAWAYtoArray. The items will be in the same exact order of the original command.
Convert-PowerDbgRUNAWAYtoArray
Returns an array of two dimensions corresponding to the output of !runaway 1 or !runaway 2.
Parse-PowerDbgK
Maps the output of k command and its variations like kv, kbn, kpn, etc.
The output is saved into the CSV file POWERDBG-PARSED.LOG
Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.
Attention! This cmdlet doesn’t work with kPn. Another thing, it replaces “ , ” with “ ; ” to avoid conflict with the CSV delimiter.
Parse-PowerDbgSymbolsFromK
Maps just the symbols from k command and variations, saving the content into the CSV file POWERDBG-PARSED.LOG
Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.
Attention! This cmdlet doesn’t work with kPn. Another thing, it replaces “ , ” with “ ; ” to avoid conflict with the CSV delimiter.
Parse-PowerDbgLM1M
Maps just the output from lm1m and stores it into the CSV file POWERDBG-PARSED.LOG
Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.
Classify-PowerDbgThreads
Returns one array where the index is the thread number and the value is one of these values:
0 UNKNOWN_SYMBOL
1 WAITING_FOR_CRITICAL_SECTION
2 DOING_IO
3 WAITING
4 GC_THREAD
5 WAIT_UNTIL_GC_COMPLETE
6 SUSPEND_FOR_GC
7 WAIT_FOR_FINALIZE
8 TRYING_MANAGED_LOCK
9 DATA_FROM_WINSOCK
It’s very easy to add more symbols and constants to get a more granular analysis. Look at the source code for details.
Analyze-PowerDbgThreads
Analyzes and shows what each thread is doing and its corresponding CPU time, sorted by User Mode time.
This cmdlet is very useful for scenarios like hangs, high CPU, and crashes.
Attention! This command requires thread information if debugging a dump file.
Parse-PowerDbgPRINTEXCEPTION
Maps the output from !PrintException command and saves it into the CSV file POWERDBG-PARSED.LOG.
The following fields are considered while others are ignored:
Exception object:
Exception type;
Message:
InnerException:
HRESULT:
Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.
Parse-PowerDbgDD-L1
Maps the output from dd <address> L1 or dd poi(<address>) L1 and saves the results into the CSV file POWERDBG-PARSED.LOG.
Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.
Parse-PowerDbgGCHANDLELEAKS
Maps the output from !GCHandleLeaks command and saves it into the CSV file POWERDBG-PARSED.LOG.
Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.
Parse-PowerDbgDUMPOBJ
Maps the output from !DumpObj command and saves it into the CSV file POWERDBG-PARSED.LOG.
The assembly path and file name are saved using the key name “Assembly:.”
If the object is invalid, the ‘Name:’ field will have the string “Invalid Object.” You may want to check this string to make sure you have valid data.
The keys are the fields or Method Table, and values are the corresponding value.
Convert-PowerDbgCSVToHashTable converts the output into a Hash Table.
Attention! This version maps the fields below “Fields:” using MethodTable as key and Value as value. The problem with this approach is that the same MethodTable may appear more than once. If it happens, the last or most recent MethodTable and value will be considered.
Based on users’ feedback this approach may be changed in the near future.
POWERDBG SCRIPTS
Extracts the key/value pair from a dictionary.
Displays the call stacks that have inner or hidden exceptions.
PowerDbgScriptGCHandleLeaksChart.PS1
Displays statistics and a chart from the top 20 objects leaking.
Displays all threads consuming high CPU using a specific time as a threshold.
Saves all modules that have a specific method. You provide the method name, and it gives you the corresponding modules.
Comments
Anonymous
April 14, 2009
PingBack from http://asp-net-hosting.simplynetdev.com/powershell-script-powerdbg-v52%e2%80%94using-powershell-to-control-windbg/Anonymous
April 15, 2009
Are all the global variables really needed? Couldn't most of them be local to the module? It's would be nice to not polute the global namespace so much... Regards, /StaffanAnonymous
April 15, 2009
Hey Staffan, I consider myself a PowerShell hobbyst. PowerDbg is my "Hello World" application, my very first PowerShell application. I decided to create it in order to learn the language and I don't use PowerShell everyday. So, considering my PowerShell knowledge I think they're necessary although I tried to avoid them, except if there's another way to share the variables among cmdlets that I'm not aware of. If you have suggestions I'd like to know. Maybe I can implement them in the next PowerDbg version. ;-) Thanks, Roberto