[PowerShell Script] Statistics from .NET Applications

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

}