[PowerShell Script] Downloading PDB for Specific Modules


A few weeks ago, during a laboratory with a customer, I found myself struggling to download the public symbol from a specific driver. Since driver is Kernel Mode if you get a User Mode dump from the application using the driver, you won’t be able to actually see and download the driver. If you have a Kernel dump, you can get the module and download the symbols, but it’s more work.


 


There are other approaches and tools, but during this lab a colleague from PFE recommended symchk.exe, which is part of Debugging Tools for Windows. It turned out to be the best approach for my needs; however, chances are I’ll forget the syntax and my customer, too. To avoid this problem, I decided to create a small script that acts as a wrapper for symchk.  To use it you have to pass 4 required parameters:


 


<Folder that Has the Modules> – Folder that has the modules (dlls/exes)


 


<Module Name or Mask> – You can use something like *.dll or the module name, like tcpip.dll.


 


<Folder To Save the Symbols>- Name for the folder that is going to store the symbols.


 


<Folder Where Debugging Tools For Windows is Installed>- Directory where Debugging tools for Windows was installed.


 


Usage:


 


Let’s suppose my dlls are in c:\test\dlls, my debugger is in c:\debuggers, and I want to save the public symbols for all dlls (*.dll) in c:\test\symbols.


Here is the command line:


 


.\GetPDBForModules “c:\test\dlls” “*.dll” “c:\test\symbols” “c:\debuggers


 


 


Before – just our binaries:


 


 


 


 


Execution:


 



 


 


After execution – binaries, symbols and manifest file:


 



 


Source code for GetPDBForModules.PS1:


  


 


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


# Script:       GetPDBforModules.ps1


#


# Parameters:   <dirModules>     – Folder that has the modules (dlls)


#               <moduleName>     – You can use something like *.dll or the module name.


#               <outputDirName>  – Name for the folder that is going to store the symbols.


#               <dirForDbgTools> – Directory where Debugging tools for Windows was installed.


#


# Purpose:      Access the Microsoft public symbols and download the symbols for each module.


#


# Requirement:  Debugging Tools For Windows.


#


# Usage:        .\GetPDBforModules “c:\modules” “ntdll.dll” “c:\symbols” “c:\debuggers”


 #              .\GetPDBforModules “c:\modules” “*.dll” “c:\symbols” “c:\debuggers”


#


# Changes History: 


#


# Roberto Alexis Farah


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


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


param(


      [string] $dirModules     = $(throw “Error! You must provide the path which has the modules like: c:\modules”),


      [string] $moduleName     = $(throw “Error! You must provide the file name like: ntdll.dll or *.dll or *.exe”),


      [string] $outputDirName  = $(throw “Error! You must provide the path which is going to store the symbols, like: c:\symbols”),


      [string] $dirForDbgTools = $(throw “Error! You must provide the path for Debugging Toos For Windows.”)


     )


set-psdebugstrict


$ErrorActionPreference = “stop”


trap {“Error message: $_”}


 


$tempFile = “Manifest.txt” # We use $outputDirName plus .txt to create the manifest text file.


 


$dirForDbgTools += “\symchk”   # Add symchk.exe to path.


 


# In case we are adding one more \, let’s remove the extra \.


$dirForDbgTools = $dirForDbgTools.Replace(“\\”, “\”)


 


# Windows Shell to call the console application.


$instance = new-objectcomobject WScript.Shell


 


write-Host “`nExtracting manifest file from module(s)…`n”foreground Green –background Black


 


$temp = “$dirModules\$moduleName”.Replace(“\\”, “\”)


 


# Creates directory. If it already exists it’s ok.


$hideOutput = md “$outputDirName”


 


# It should be something like: symchk /om C:\SymListManifest /if c:\WINDOWS\system32\*.dll


$argument = “$dirForDbgTools /om $outputDirName$tempFile /if $temp”


 


write-Host  $argumentforeground Red –background Black


 


$output = $instance.Run($argument, 3)


 


# The Run() method from WshShell doesn’t wait for the callee to finish the execution, so let’s wait for 10 seconds.


# On next version let’s monitor if the console window had disappeared, so we don’t have to use the forced delay.


start-Sleep 10


 


write-Host “`nDone!”foreground Green –background Black


write-Host “`nDownloading symbols to $outputDirName folder…”foreground Green –background Black


 


$argument = “$dirForDbgTools /im $outputDirName$tempFile /s SRV*$outputDirName*http://msdl.microsoft.com/download/symbols”


write-Host  $argumentforeground Red –background Black


 


$output = $instance.Run($argument, 3)


 


write-Host “`nDone! “  foreground Green –background Black –nonewline


write-Host $outputDirName  foreground Red –background Black –nonewline


write-Host ” has all requested PDB files.`n”  foreground Green –background Black