Analyser un dump de worker process avec PowerShell / Worker process dump analysis with PowerShell
[MAJ 24/06/2016] Il y a quelques semaines un de mes collègues (Merci Julien !), m'a fait découvrir PowerDbg. PowerDbg est une librairie PowerShell vous permettant de créer facilement des scripts PowersShell pour automatiser des sessions de debugging WinDbg / CDB (plus de détails ici). Ce collègue m'envoya un exemple d'utilisation de PowerDbg pour le debug d'une application ASP.Net au sein d'un worker processus IIS - w3wp.exe). J'ai décidé de développer une version "full" PowerShell de cet exemple (J'ai supprimé des dépences externes de la version originale) que je vous propose dans cet article (le fichier source est disponible ici). Dans cet exemple je charge seulement 2 extensions - SOS and CLR - et je lance seulement deux commandes - !pe and !ClrStack. Vous pouvez personnaliser ou ajouter les extensions que vous voulez charger et les commandes associées. Le résultat est un fichier CSV ressemblant à peu près à celui-ci (sortie volontairement tronquée) :
Si vous désirez générer des dumps de worker processus vous pouvez jeter un coup d'oeil à ces deux ressources :
- https://blogs.msdn.microsoft.com/friis/2010/04/01/application-de-test-pour-gnrer-des-dumps-iis/ (Equipe support IIS/Azure France)
- https://msdn.microsoft.com/en-us/library/bb397417.aspx (J'ai utilisé ce code pour générer mon dump dans la capture d'écran ci-dessus)
[Updated 06/24/2016] Some weeks ago a colleague of mine (Thanks Julien !),pointed me to PowerDbg. PowerDbg is a PowerShell library that enables you to easily create PowerShell scripts to automate a WinDbg / CDB debugging session (further details here). This colleague sent to me a PowerDbg use case for debugging an ASP.Net application (inside an IIS worker process - w3wp.exe). I decided to build a full PowerShell version of this example (I removed some external depencies of the original version) and I propose it to you in this article (the source file is available here). In this example I load only 2 extensions - SOS and CLR - and I run only two commands - !pe and !ClrStack. You can add or customize the extensions you want to load and the related commands. The result is a CSV file looking like this one (output was truncated):
If you want generate worker process dumps you can take a look at this two resources :
- https://blogs.msdn.microsoft.com/friis/2010/04/01/application-de-test-pour-gnrer-des-dumps-iis/ (French IIS/Azure Support Team)
- https://msdn.microsoft.com/en-us/library/bb397417.aspx (I used this code to generate my dump used in the screenshot above)
#requires -version 2
#requires -Module PowerDbg
Import-Module -Name PowerDbg
#region My function definitions
function New-PDBGCrashAnalysis
{
<#
.SYNOPSIS
Runs a debugging session for the dump(s) passed as parameter(s)
.DESCRIPTION
Runs a debugging session for the dump(s) passed as parameter(s)
.PARAMETER FullName
The full file path of the dump(s) to analyze
.EXAMPLE
New-PDBGCrashAnalysis -FullName "C:\Tools\Dumps\w3wp.exe_160518_000457.dmp", "C:\Tools\Dumps\w3wp.exe_160518_002041.dmp" -Verbose
Runs a debugging session for the two specified worker process dumps ("C:\Tools\Dumps\w3wp.exe_160518_000457.dmp", "C:\Tools\Dumps\w3wp.exe_160518_002041.dmp" )
.EXAMPLE
Get-ChildItem -Path 'C:\Temp' -Filter 'w3wp*.dmp' -Recurse | New-PDBGCrashAnalysis -Verbose
Returns all worker processes dumps in the C:\Temp folder (and its subfolders) and runs a debugging session for all of them.
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)]
#The BLG File to convert : Checking if the file exists and has the .dmp extension
[ValidateScript({
(Test-Path -Path $_ -PathType Leaf) -and ($_ -match '\.dmp$')
})]
[alias('Source', 'Dump')]
[String[]]$FullName
)
begin
{
#Array for storing the results
$Analyses = @()
}
process
{
#For all files passed as argument outside a pipeline context
Foreach ($CurrentFullName in $FullName)
{
Write-Verbose -Message "Processing $CurrentFullName ..."
# Close proactively any existing debugger session if already connected for some reason
Exit-DbgSession #Disconnect-Windbg
Write-Verbose -Message 'Closing proactively any existing debugger session if already connected for some reason ...'
Write-Verbose -Message 'Creating new DBG Session.'
New-DbgSession -Dump $CurrentFullName
Write-Verbose -Message 'Loading sos and clr extensions'
Load-DbgExtension sos
Load-DbgExtension clr
#Invoke-DbgCommand !pe2
Write-Verbose -Message 'Invoking DBG command : !pe'
$Exception = Invoke-DbgCommand !pe
Write-Verbose -Message 'Invoking DBG command : !ClrStack'
$ClrStack = Invoke-DbgCommand !ClrStack
Write-Verbose -Message "Exception : $Exception "
Write-Verbose -Message "ClrStack : $ClrStack "
$Analyses += New-Object -TypeName PSObject -Property @{
FullName = $CurrentFullName
Exception = $Exception[1]
Message = $Exception[2]
ClrStack = $ClrStack -join "`r`n"
}
Write-Verbose -Message 'Disconnecting new DBG Session'
Exit-DbgSession #Disconnect-Windbg
}
}
end
{
#returning the data array
return $Analyses
}
}
#endregion
Clear-Host
# Getting the this script path
$CurrentScript = $MyInvocation.MyCommand.Path
# Getting the directory of this script
$CurrentDir = Split-Path -Path $CurrentScript -Parent
# Creating CSV file name based on the script full file path and by appending the timestamp at the end of the file name
$CSVFile = $CurrentScript.replace((Get-Item -Path $CurrentScript).Extension, '_'+$(Get-Date -Format 'yyyyMMddTHHmmss')+'.csv')
# Without pipeline use
#$Analyses = New-PDBGCrashAnalysis -FullName "C:\Tools\Dumps\w3wp.exe_160518_000457.dmp", "C:\Tools\Dumps\w3wp.exe_160518_002041.dmp" -Verbose
# With pipeline use
# Looking for dumps in the script folder (and subfolders)
$Analyses = Get-ChildItem -Path $CurrentDir -Filter 'w3wp*.dmp' -Recurse | New-PDBGCrashAnalysis -Verbose
$Analyses |
Group-Object -Property Message |
Sort-Object -Property Count -Descending |
Select-Object -Property @{
Name = 'Message'
Expression = {
$_.Name
}
}, Count
#$Analyses | Format-List * -Force
$Analyses | Export-Csv -Path $CSVFile -Force -NoTypeInformation
Write-Host -Object "Results are available in '$CSVFile'"
Laurent.