This script is more a template to show you how to use PowerDbg.

I must say the idea is from my teammate Aaron Barth!

This script collects information from all threads running managed code and gives the user statistics by threads like:

 

-      CLR stack.

-      Managed objects from the stack.

-      ASP.NET page.

-      What the thread is doing.

-      Exceptions by threads.

-      Threads running ASP.NET pages.

 

Contrary to what you may think, this script is very simple. It’s very easy to customize or improve it. For example, you may want to display the ASP.NET pages or queries/stored procedures by threads. Or you may want to create a report using HTML. The output from this script is text, simple and straight. Again, the idea is to show you how to use the cmdlets from PowerDbg in order to create scripts that automate the debugging session.

 

Screenshots:

 

 

 

 

 

 

 

 

 

Source code for PowerShellScriptASPXStatistics.ps1:

 

########################################################################################################

# Script:      PowerDbgScriptASPXStatistics

#

# Parameters:  None.

#

# Purpose:     Shows statistics from threads running ASP.NET pages.

#

#              Attention! This script was not tested on Win64.

#

# Changes History: 04/15/2009 – Fixed bug when there’s just one managed thread.

#

# Roberto Alexis Farah

# All my functions are provided "AS IS" with no warranties, and confer no rights.

########################################################################################################

set-psdebug -strict

$ErrorActionPreference = "stop"

trap {"Error message: $_"}

 

write-Host "Scanning all threads and extracting the CLR stack..." -foreground Green -background Black

 

# First, let's scan all threads and identify those running managed code.

Send-PowerDbgCommand "~* e !clrstack"

Parse-PowerDbgCLRSTACK

 

# Get all the stacks running managed code.

$clrStack = Convert-PowerDbgCSVToHashTable

 

write-Host "Done!" -foreground Green -background Black

 

# Sorts the keys by Thread Number and save them into an array.

$arrayOfThreads = @($clrStack.keys | Sort-Object {[int] $_})

 

# Let's consider the situation where the dump has no thread running managed code.

if($arrayOfThreads.Count -eq 0)

{

    write-Host "There are not threads running managed code!" -foreground Red -background Black

    return

}

 

write-Host "Scanning all threads and extracting the managed objects..." -foreground Green -background Black

 

Send-PowerDbgCommand "~* e !dso"

Parse-PowerDbgDSO

 

$dso = Convert-PowerDbgCSVToHashTable

 

write-Host "Done!" -foreground Green -background Black

 

write-Host "Collecting information about each thread..." -foreground Green -background Black

 

Send-PowerDbgCommand "!Threads"

Parse-PowerDbgTHREADS

 

$threads = Convert-PowerDbgCSVToHashTable

 

write-Host "Done!" -foreground Green -background Black

 

write-Host "Collecting information from threads running ASP.NET..." -foreground Green -background Black

 

Send-PowerDbgCommand "!ASPXPages"

Parse-PowerDbgASPXPAGES

 

$aspxPages = Convert-PowerDbgCSVToHashTable

 

write-Host "Done!" -foreground Green -background Black

 

write-Host "Scanning all threads and preparing statistics..." -foreground Green -background Black

 

# Scans all threads running managed code.

for($i = 0; $i -lt $arrayOfThreads.Length; $i++)

{

    # Make sure the content is not null.

    if($arrayOfThreads[$i] -eq "")

    {

        continue;  # Invalid, get next element.

    }

   

    write-Progress -activity "Thread Statistics" -status "Thread number $arrayOfThreads[$i]" -percentComplete ($i / $arrayOfThreads.length * 100)

   

    write-Host "==============================================================" -foreground Green -background Black

   

    write-Host "`nThread number: " -foreground Green -background Black -nonewline

    write-Host $arrayOfThreads[$i] -foreground Red -background Black

   

    write-Host "`nCLR stack:`n" -foreground Green -background Black

   

    [string] $temp = $clrstack[$arrayOfThreads[$i]]

    $temp = $temp.Replace($global:g_frameDelimiter, "`n")

    $temp = $temp.Replace(";", ",")

   

    write-Host $temp -foreground Red -background Black

   

    write-Host "`nManaged objects from the stack:`n" -foreground Green -background Black

   

    $temp = $dso[$arrayOfThreads[$i]]

   

    $temp = $temp.Replace($global:g_frameDelimiter, "`n")

    $temp = $temp.Replace(";", ",")

   

    write-Host $temp -foreground Red -background Black 

 

    write-Host "`nThread Number   ID OSID ThreadOBJ   State   GC       Context           Domain  Count APT Exception`n" -foreground Green -background Black

 

    write-Host "  " $arrayOfThreads[$i] "         " $threads[$arrayOfThreads[$i]] -foreground Red -background Black

   

    $threadNum = $arrayOfThreads[$i]

   

    # Change context to the current thread being analyzed.

    Send-PowerDbgCommand "~ $threadNum s"

   

    # Get exception.

    Send-PowerDbgCommand "!PrintException"

    Parse-PowerDbgPRINTEXCEPTION

   

    $exception = $null

    $exception = Convert-PowerDbgCSVToHashTable

   

    # Makes sure there is an exception coming from that thread.

    if($exception["Message:"] -ne $null)

    {

        write-Host "`nException object:" -foreground Green -background Black    

        write-Host $exception["Exception object:"] -foreground Red -background Black

        write-Host "Exception type:" -foreground Green -background Black           

        write-Host $exception["Exception type:"] -foreground Red -background Black       

        write-Host "Message:" -foreground Green -background Black           

        write-Host $exception["Message:"] -foreground Red -background Black       

        write-Host "Inner Exception:" -foreground Green -background Black           

        write-Host $exception["InnerException:"] -foreground Red -background Black

        write-Host "HRESULT:" -foreground Green -background Black           

        write-Host $exception["HResult:"] -foreground Red -background Black        

    }

 

    # User must press any key to continue after 5 threads were displayed.

    if((($i + 1) % 5) -eq 0)

    {

        write-Host "`n####### Press any key to see 5 more threads... #######"

        $keyboard = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

    }

}

 

write-Host "Done!" -foreground Green -background Black

 

write-Host "`nASP.NET Pages:`n" -foreground Green -background Black

 

write-Host "HttpContext      Timeout Completed Running ThreadId ReturnCode Verb RequestPath QueryString" -foreground Green -background Black

 

foreach($item in $aspxPages.keys)

{

    write-Host $item  "  " $aspxPages[$item] -foreground Red -background Black

}