########################################################################################################
# PowerDbg v 2.3
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
# Global variables.
########################################################################################################
$global:g_instance = $null
$global:g_fileParsedOutput = "POWERDBG-PARSED.LOG"
$global:g_fileCommandOutput = "POWERDBG-OUTPUT.LOG"
$global:g_CSVDelimiter = ","
$global:g_frameDelimiter = "#$#@"
# It's not possible to create an enum like C++/C# using a PowerShell keyword.
# The PowerShell blog has a solution for it, but here I'm going to use local variables.
$global:g_unknownSymbol = 0
$global:g_waitingForCriticalSection = 1
$global:g_doingIO = 2
$global:g_threadWaiting = 3
$global:g_GCthread = 4
$global:g_waitUntilGCComplete = 5
$global:g_suspendForGC = 6
$global:g_waitForFinalize = 7
$global:g_tryingGetLock = 8
$global:g_winSockReceivingData = 9
$global:g_finalizerThread = 10
$global:g_CLRDebuggerThread = 11
$global:g_w3wpMainThread = 12
$global:g_threadPool = 13
$global:g_CompressionThreaad = 14
$global:g_COMcall = 15
$global:g_CLRWorkerThread = 16
$global:g_completionPortIOThread = 17
$global:g_gateThread = 18
$global:g_timerThread = 19
$global:g_unloadAppDomainThread = 20
$global:g_RPCWorkerThread = 21
$global:g_LPRCWorkerThread = 22
$global:g_hostSTAThread = 23
# The array below has the meaning of each constant above. It can be used to display high level information
# to the user.
$global:g_whatThreadIsDoing =
@(
"Thread working and doing unknown activity.", # 0
"Thread waiting for Critical Section.", # 1
"Thread doing I/O operation.", # 2
"Thread in wait state.", # 3
"Thread from Garbage Collector.", # 4
"Thread waiting for the Garbage Collector to complete.", # 5
"Thread is being suspended to perform a Garbage Collector." # 6
"Thread waiting for the Finalizer event. The Finalizer thread might be blocked.", # 7
"Thread trying to get a managed lock.", # 8
"Thread receiving or trying to receive data. The data might be from the database.", # 9
"Thread is the Finalizer Thread.", # 10
"Thread is the CLR Debugger Thread.", # 11
"Thread is the W3WP.EXE main thread.", # 12
"Thread is from the W3WP.EXE pool of threads.", # 13
"Thread is a Compression Thread from W3WP.EXE.", # 14
"Thread doing a COM call.", # 15
"Thread is a CLR Worker Thread.", # 16
"Thread is a Completion Port I/O Thread.", # 17
"Thread is a CLR Gate Thread.", # 18
"Thread is a CLR Timer Thread.", # 19
"Thread is an Unload Application Domain Thread.", # 20
"Thread is a RPC Worker Thread.", # 21
"Thread is an LRPC Worker Thread.", # 22
"Thread is the Host STA Thread." # 23
)
########################################################################################################
# Function: Start-PowerDbgWinDbg
#
# Parameters: [string] <$debuggerPathExe>
# Path and executable where is located your WinDbg.
#
# [string] <$nameOfDumpOrProcess>
# Name of dump file or process to debug. The process must be running.$#
#
# [string] <$symbolPath>
# Specifies the symbol file search path. Separate multiple paths with a semicolon (;).
#
# Return: Global variable $debuggerInstance that has the debugger instance.
#
# Purpose: Start an WinDbg $g_instance and open a dump file or attach to a running process.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Start-PowerDbgWinDbg(
[string] $debuggerPathExe = $(throw "Error! You must provide the Windbg path."),
[string] $nameOfDumpOrProcess = $(throw "Error! You must provide dump file or process name."),
[string] $symbolPath = $(throw "Error! You must provide the symbol path.")
)
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
$debugger = $debuggerPathExe
$isExe = $false
# Check if the argument is a dump file or process name and use the corresponding WinDbg command.
if($nameOfDumpOrProcess -ilike "*.dmp")
{
$debugger += " -z " + $nameOfDumpOrProcess
}
elseif($nameOfDumpOrProcess -ilike "*.exe")
{
$isExe = $true
}
else
{
throw "Error! You must provide a valid dump file or executing process."
}
if($isExe)
{
$debugger += " -Q -QSY -QY -v -y " + "`"$symbolPath`"" + " -c `".symfix;.reload`"" + " -T PowerDbg" + " " + $nameOfDumpOrProcess
}
else
{
$debugger += " -Q -QSY -QY -v -y " + "`"$symbolPath`"" + " -c `".symfix;.reload`"" + " -T PowerDbg"
}
# Now we can start a new debugger instance.
$global:g_instance = new-object -comobject WScript.Shell
$output = $global:g_instance.Run($debugger, 3)
# Maximize window. It's not necessary to use the full name.
$output = $global:g_instance.AppActivate("PowerDbg")
}
########################################################################################################
# Function: Send-PowerDbgCommand
#
# Parameters: [string] <$command>
# Command from Windbg. Avoid mixing more than one command at the same line to be easier to parse the output.
#
# Return: Nothing.
#
# Purpose: Sends a command to the Windbg instance that has the PowerDbg title and saves the command and its output
# into a log file named POWERDBG.LOG.
# If there's no instance that has the PowerDbg title you need to use the .wtitle command from WinDbg
# and change the WinDbg window in order to start with the PowerDbg string.
# The command output will be into the POWERDBG-OUTPUT.LOG.
# Your parser functions should use POWERDBG-OUTPUT.LOG.
#
# Changes History: 12/31/2007 - In a few specific scenarios the .logopen command may not create the log file.
# Now the POWERDBG.LOG is tested. If it was not created, the function tries to
# create it for a limited number of times.
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Send-PowerDbgCommand([string] $command = $(throw "Error! You must provide a Windbg command."))
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
# First let's locate if Start-PowerDbgWinDbg had created an WinDbg instance.
# If not, let's try to use one running instance.
if($global:g_instance -eq $null)
{
$global:g_instance = new-object -comobject WScript.Shell
}
# Set focus to Windbg instance.
$return = $global:g_instance.AppActivate("PowerDbg")
start-sleep 1
# Set focus to Command window.
$return = $global:g_instance.AppActivate("Command")
start-sleep 1
# Get the directory where the log will be created.
$aux = get-Process windbg
# We may have several instances. That's why I use element 0.
if($aux.Count -gt 0)
{
$aux = $aux[0].MainModule.Filename
}
else
{
$aux = $aux.MainModule.Filename
}
$aux = [System.IO.Path]::GetDirectoryName($aux)
$logFile = "$aux\POWERDBG.LOG"
$fileExists = test-Path $logFile
# Remove log file, so we can know if it was created.
if($fileExists -eq $true)
{
remove-Item $logFile
}
# Create log.
$output = $global:g_instance.SendKeys(".logopen $logFile")
$output = $global:g_instance.SendKeys("{ENTER}")
# If POWERDBG.LOG was not created, try it again for 5 times.
for([System.Int32] $count = 0; $count -lt 5; $count++)
{
start-Sleep 1
$fileExists = test-Path $logFile
# If the log file was created leaves the loop.
if($fileExists -eq $true)
{
break
}
else # If not, tries to create it again, for 5 more times.
{
# Tries to create log again.
$output = $global:g_instance.SendKeys(".logopen $logFile")
$output = $global:g_instance.SendKeys("{ENTER}")
}
}
# Adjust specific commands.
$command = $command.Replace("~", "{~}")
$command = $command.Replace("%", "{%}")
$command = $command.Replace("+", "{+}")
# Send command.
$output = $global:g_instance.SendKeys($command)
$output = $global:g_instance.SendKeys("{ENTER}")
# Close log, saving last command and its output.
$output = $global:g_instance.SendKeys(".logclose")
$output = $global:g_instance.SendKeys("{ENTER}")
# A delay is required here.
start-sleep 3
# Extract output removing commands.
$builder = New-Object System.Text.StringBuilder
get-content "$aux\POWERDBG.LOG" | foreach-object {if(($_ -notmatch "^.:...>") -and ($_ -notmatch "^Opened log file") -and ($_ -notmatch "^Closing open log file")){$builder = $builder.AppendLine([string] $_)}}
# Save the output into a file. The location is the same you are executing PowerDbg.
out-file -filepath $global:g_fileCommandOutput -inputobject "$builder"
}
########################################################################################################
# Function: Parse-PowerDbgDT
#
# Parameters: [switch] [$useFieldNames]
# Switch flag. If $useFieldNames is present then the function saves the field
# names from struct/classes and their values. Otherwise, it creates saves the offsets
# and their values.
#
# Return: Nothing.
#
# Purpose: Maps the output from the "dt" command using a hash table. The output
# is saved into the file POWERDBG-PARSED.LOG
# All Parse functions should use the same outputfile.
# You can easily map the POWERDBG-PARSED.LOG to a hash table.
# Convert-PowerDbgCSVtoHashTable() does that.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Parse-PowerDbgDT([switch] $useFieldNames)
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
# Extract output removing commands.
$builder = New-Object System.Text.StringBuilder
# Title for the CSV fields.
$builder = $builder.AppendLine("key,value")
# \s+ --> Scans for one or more spaces.
# (\S+) --> Gets one or more chars/digits/numbers without spaces.
# \s+ --> Scans for one or more spaces.
# (\w+) --> Gets one or more chars.
# .+ --> Scans for one or more chars (any char except for new line).
# \: --> Scans for the ':' char.
# \s+ --> Scans for one or more spaces.
# (.+.) --> Gets the entire remainder string including the spaces.
if($useFieldNames)
{
foreach($line in $(get-content $global:g_fileCommandOutput))
{
if($line -match "0x\S+\s+(?<key>\w+).+\:\s+(?<value>.+)")
{
$builder = $builder.AppendLine($matches["key"] + $global:g_CSVDelimiter + $matches["value"])
}
}
}
else
{
foreach($line in $(get-content $global:g_fileCommandOutput))
{
if($line -match "(?<key>0x\S+).+\:\s+(?<value>.+)")
{
$builder = $builder.AppendLine($matches["key"] + $global:g_CSVDelimiter + $matches["value"])
}
}
}
# Send output to our default file.
out-file -filepath $global:g_fileParsedOutput -inputobject "$builder"
}
########################################################################################################
# Function: Convert-PowerDbgCSVtoHashTable
#
# Parameters: None.
#
# Return: Hash table.
#
# Purpose: Sometimes the Parse-PowerDbg#() functions return a CSV file. This function
# loads the data using a hash table.
# However, it works just when the CSV file has two fields: key and value.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Convert-PowerDbgCSVtoHashTable()
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
$hashTable = @{}
import-csv -path $global:g_fileParsedOutput | foreach {$hashTable[$_.key] = $_.value}
return $hashTable
}
########################################################################################################
# Function: Send-PowerDbgDML
#
# Parameters: [string] <$hyperlinkDML>
# Hyperlink for the DML command.
#
# [string] <$commandDML>
# Command to execute when the hyperlink is clicked.
#
# Return: Nothing.
#
# Purpose: Creates a DML command and send it to Windbg.
# DML stands for Debug Markup Language. Using DML you can create hyperlinks that
# run a command when the user click on them.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Send-PowerDbgDML(
[string] $hyperlinkDML = $(throw "Error! You must provide the hyperlink for DML."),
[string] $commandDML = $(throw "Error! You must provide the command for DML.")
)
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
Send-PowerDbgCommand ".printf /D `"<link cmd=\`"$commandDML\`"><b>$hyperlinkDML</b></link>\n\`"`""
}
########################################################################################################
# Function: Parse-PowerDbgNAME2EE
#
# Parameters: None.
#
# Return: Nothing.
#
# Purpose: Maps the output from the "!name2ee" command using a hash table. The output
# is saved into the file POWERDBG-PARSED.LOG
# All Parse functions should use the same outputfile.
# You can easily map the POWERDBG-PARSED.LOG to a hash table.
# Convert-PowerDbgCSVtoHashTable() does that.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Parse-PowerDbgNAME2EE()
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
# Extract output removing commands.
$builder = New-Object System.Text.StringBuilder
# Title for the CSV fields.
$builder = $builder.AppendLine("key,value")
# \s+ --> Scans for one or more spaces.
# (\S+) --> Gets one or more chars/digits/numbers without spaces.
# \s+ --> Scans for one or more spaces.
# (\w+) --> Gets one or more chars.
# .+ --> Scans for one or more chars (any char except for new line).
# \: --> Scans for the ':' char.
# \s+ --> Scans for one or more spaces.
# (.+.) --> Gets the entire remainder string including the spaces.
foreach($line in $(get-content $global:g_fileCommandOutput))
{
# Attention! The Name: doesn't map to the right value, however, it should be the same method name provide as argument.
if($line -match "(?<key>\w+\:)\s+(?<value>\S+)")
{
$builder = $builder.AppendLine($matches["key"] + $global:g_CSVDelimiter + $matches["value"])
}
}
# Send output to our default file.
out-file -filepath $global:g_fileParsedOutput -inputobject "$builder"
}
########################################################################################################
# Function: Parse-PowerDbgDUMPMD
#
# Parameters: None.
#
# Return: Nothing.
#
# Purpose: Maps the output from the "!dumpmd" command using a hash table. The output
# is saved into the file POWERDBG-PARSED.LOG
# All Parse functions should use the same outputfile.
# You can easily map the POWERDBG-PARSED.LOG to a hash table.
# Convert-PowerDbgCSVtoHashTable() does that.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Parse-PowerDbgDUMPMD()
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
# Extract output removing commands.
$builder = New-Object System.Text.StringBuilder
# Title for the CSV fields.
$builder = $builder.AppendLine("key,value")
# \s+ --> Scans for one or more spaces.
# (\S+) --> Gets one or more chars/digits/numbers without spaces.
# \s+ --> Scans for one or more spaces.
# (\w+) --> Gets one or more chars.
# .+ --> Scans for one or more chars (any char except for new line).
# \: --> Scans for the ':' char.
# \s+ --> Scans for one or more spaces.
# (.+.) --> Gets the entire remainder string including the spaces.
foreach($line in $(get-content $global:g_fileCommandOutput))
{
if($line -match "(?<key>((^Method Name :)|(^MethodTable)|(^Module:)|(^mdToken:)|(^Flags :)|(^Method VA :)))\s+(?<value>\S+)")
{
$builder = $builder.AppendLine($matches["key"] + $global:g_CSVDelimiter + $matches["value"])
}
}
# Send output to our default file.
out-file -filepath $global:g_fileParsedOutput -inputobject "$builder"
}
########################################################################################################
# Function: Parse-PowerDbgDUMPMODULE
#
# Parameters: None.
#
# Return: Nothing.
#
# Purpose: Maps the output from the "!dumpmodule" command using a hash table. The output
# is saved into the file POWERDBG-PARSED.LOG
# All Parse functions should use the same outputfile.
# You can easily map the POWERDBG-PARSED.LOG to a hash table.
# Convert-PowerDbgCSVtoHashTable() does that.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Parse-PowerDbgDUMPMODULE()
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
# Extract output removing commands.
$builder = New-Object System.Text.StringBuilder
# Title for the CSV fields.
$builder = $builder.AppendLine("key,value")
[int] $countFields = 0
# \s+ --> Scans for one or more spaces.
# (\S+) --> Gets one or more chars/digits/numbers without spaces.
# \s+ --> Scans for one or more spaces.
# (\w+) --> Gets one or more chars.
# .+ --> Scans for one or more chars (any char except for new line).
# \: --> Scans for the ':' char.
# \s+ --> Scans for one or more spaces.
# (.+.) --> Gets the entire remainder string including the spaces.
foreach($line in $(get-content $global:g_fileCommandOutput))
{
# Fields for .NET Framework 2.0
if($line -match "(?<key>((^dwFlags)|(^Assembly:)|(^LoaderHeap:)|(^TypeDefToMethodTableMap:)|(^TypeRefToMethodTableMap:)|(^MethodDefToDescMap:)|(^FieldDefToDescMap:)|(^MemberRefToDescMap:)|(^FileReferencesMap:)|(^AssemblyReferencesMap:)|(^MetaData start address:)))\s+(?<value>\S+)")
{
$builder = $builder.AppendLine($matches["key"] + $global:g_CSVDelimiter + $matches["value"])
$countFields++
}
}
# If nothing was found, let's try to use the .NET Framework 1.1 fields.
if($countFields -lt 3)
{
foreach($line in $(get-content $global:g_fileCommandOutput))
{
# Fields for .NET Framework 2.0
if($line -match "(?<key>((^dwFlags)|(^Assembly\*)|(^LoaderHeap\*)|(^TypeDefToMethodTableMap\*)|(^TypeRefToMethodTableMap\*)|(^MethodDefToDescMap\*)|(^FieldDefToDescMap\*)|(^MemberRefToDescMap\*)|(^FileReferencesMap\*)|(^AssemblyReferencesMap\*)|(^MetaData starts at)))\s+(?<value>\S+)")
{
$builder = $builder.AppendLine($matches["key"] + $global:g_CSVDelimiter + $matches["value"])
$hasFound = $true
}
}
}
# Send output to our default file.
out-file -filepath $global:g_fileParsedOutput -inputobject "$builder"
}
########################################################################################################
# Function: Parse-PowerDbgLMI
#
# Parameters: None.
#
# Return: Nothing.
#
# Purpose: Maps the output from the "!lmi" command using a hash table. The output
# is saved into the file POWERDBG-PARSED.LOG
# All Parse functions should use the same outputfile.
# You can easily map the POWERDBG-PARSED.LOG to a hash table.
# Convert-PowerDbgCSVtoHashTable() does that.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Parse-PowerDbgLMI()
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
# Extract output removing commands.
$builder = New-Object System.Text.StringBuilder
# Title for the CSV fields.
$builder = $builder.AppendLine("key,value")
# \s+ --> Scans for one or more spaces.
# (\S+) --> Gets one or more chars/digits/numbers without spaces.
# \s+ --> Scans for one or more spaces.
# (\w+) --> Gets one or more chars.
# .+ --> Scans for one or more chars (any char except for new line).
# \: --> Scans for the ':' char.
# \s+ --> Scans for one or more spaces.
# (.+.) --> Gets the entire remainder string including the spaces.
foreach($line in $(get-content $global:g_fileCommandOutput))
{
if($line -match "(?<key>((^.+\:)))\s+(?<value>\S+)")
{
$strNoLeftSpaces = $matches["key"]
$strNoLeftSpaces = $strNoLeftSpaces.TrimStart()
$builder = $builder.AppendLine($strNoLeftSpaces + $global:g_CSVDelimiter + $matches["value"])
}
}
# Send output to our default file.
out-file -filepath $global:g_fileParsedOutput -inputobject "$builder"
}
########################################################################################################
# Function: Has-PowerDbgCommandSucceeded
#
# Parameters: None.
#
# Return: Return $true if the last command succeeded or $false if not.
#
# Purpose: Return $true if the last command succeeded or $false if not.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Has-PowerDbgCommandSucceeded
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
# Extract output removing commands.
$builder = New-Object System.Text.StringBuilder
foreach($line in $(get-content $global:g_fileCommandOutput))
{
if($line -imatch "(Fail) | (Failed) | (Error) | (Invalid) | (Unable to get) | (Exception)")
{
return $false
}
}
return $true
}
########################################################################################################
# Function: Send-PowerDbgComment
#
# Parameters: [string] $comment
# Comment to be sent to the debugger.
#
# Return: Nothing.
#
# Purpose: Sends a bold comment to the debugger. Uses DML.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Send-PowerDbgComment(
[string] $comment = $(throw "Error! You must provide a comment.")
)
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
Send-PowerDbgCommand ".printf /D `"\n<b>$comment</b>\n\n\`"`""
}
########################################################################################################
# Function: Parse-PowerDbgVERTARGET
#
# Parameters: None.
#
# Return: Nothing.
#
# Purpose: Maps the output of Kernel time and User time from "vertarget" command, using a hash table. The output
# is saved into the file POWERDBG-PARSED.LOG
# The number of days is ignored in this version.
# All Parse functions should use the same outputfile.
# You can easily map the POWERDBG-PARSED.LOG to a hash table.
# Convert-PowerDbgCSVtoHashTable() does that.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Parse-PowerDbgVERTARGET()
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
# Extract output removing commands.
$builder = New-Object System.Text.StringBuilder
# Title for the CSV fields.
$builder = $builder.AppendLine("key,value")
# \s+ --> Scans for one or more spaces.
# (\S+) --> Gets one or more chars/digits/numbers without spaces.
# \s+ --> Scans for one or more spaces.
# (\w+) --> Gets one or more chars.
# .+ --> Scans for one or more chars (any char except for new line).
# \: --> Scans for the ':' char.
# \s+ --> Scans for one or more spaces.
# (.+.) --> Gets the entire remainder string including the spaces.
foreach($line in $(get-content $global:g_fileCommandOutput))
{
if($line -match "(?<key>((Kernel time:)|(User time:)))\s+\d+\s+\S+\s+(?<value>\d+\:\d+\:\d+\.\d+)")
{
$builder = $builder.AppendLine($matches["key"] + $global:g_CSVDelimiter + $matches["value"])
}
}
# Send output to our default file.
out-file -filepath $global:g_fileParsedOutput -inputobject "$builder"
}
########################################################################################################
# Function: Parse-PowerDbgRUNAWAY
#
# Parameters: None.
#
# Return: Nothing.
#
# Purpose: Maps the output of "!runaway 1" or "!runaway 2" command, using a hash table.
# For this version the number of days is not being considered.
# The output is saved into the file POWERDBG-PARSED.LOG
# All Parse functions should use the same outputfile.
# You can easily map the POWERDBG-PARSED.LOG to a hash table.
# Convert-PowerDbgCSVtoHashTable() does that.
#
# Attention! If you need to know the top threads consuming CPU time use the Convert-PowerDbgRUNAWAYtoArray
# instead of this command. With Convert-PowerDbgRUNAWAYtoArray, the array has the exact same order of the
# original command.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Parse-PowerDbgRUNAWAY()
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
# Extract output removing commands.
$builder = New-Object System.Text.StringBuilder
# Title for the CSV fields.
$builder = $builder.AppendLine("key,value")
# \s+ --> Scans for one or more spaces.
# (\S+) --> Gets one or more chars/digits/numbers without spaces.
# \s+ --> Scans for one or more spaces.
# (\w+) --> Gets one or more chars.
# .+ --> Scans for one or more chars (any char except for new line).
# \: --> Scans for the ':' char.
# \s+ --> Scans for one or more spaces.
# (.+.) --> Gets the entire remainder string including the spaces.
foreach($line in $(get-content $global:g_fileCommandOutput))
{
if($line -match "(?<key>(\d+))\:\S+\s+\d+\s+\S+\s+(?<value>\d+\:\d+\:\d+\.\d+)")
{
$builder = $builder.AppendLine($matches["key"] + $global:g_CSVDelimiter + $matches["value"])
}
}
# Send output to our default file.
out-file -filepath $global:g_fileParsedOutput -inputobject "$builder"
}
########################################################################################################
# Function: Convert-PowerDbgRUNAWAYtoArray
#
# Parameters: None.
#
# Return: Two dimensions array.
#
# Purpose: After executing the !runaway 1 or !runaway 2, use this command to put the information into
# an array.
#
# Changes History:
#
# Roberto Alexis Farah
# All my functions are provided "AS IS" with no warranties, and confer no rights.
########################################################################################################
function Convert-PowerDbgRUNAWAYtoArray()
{
set-psdebug -strict
$ErrorActionPreference = "stop"
trap {"Error message: $_"}
# We need to count line numbers to be able to create the array.
# This particular command extracts the information from the command output file.
$num = get-Content $global:g_fileCommandOutput
# Now, we create a multidimensional array.
# We need to discard 3 lines that corresponds to:
# User Mode Time
# Thread Time
# and one extra white line.
$arrayFromRUNAWAY = new-Object 'object[,]' ($num.Length - 3),2
[System.Int32] $i = 0 # Counter.
foreach($line in $(get-content $global:g_fileCommandOutput))
{
if($line -match "(?<key>(\d+))\:\S+\s+\d+\s+\S+\s+(?<value>\d+\:\d+\:\d+\.\d+)")
{
$arrayFromRUNAWAY[$i, 0] = $matches["key"]
$arrayFromRUNAWAY[$i, 1] = $matches["value"]
$i++
}
}
# The cmoma below is very important, otherwise the function will return a single dimension array.
return ,$arrayFromRUNAWAY
}
########################################################################################################
# Function: Parse-PowerDbgK
#
# Parameters: None.
#