Error messages are a fact of life for PC users. Usually it's a straightforward process to troubleshoot where an error message came from, then continue to investigate why this error occurred. But sometimes it may be a complete mystery where an error came from, be it a message dialog box or a global log entry such as an event log error. This scenario is more common for system administrators who experience errors on unattended servers and only realize the message hours or even days later. In this article, I'll demonstrate two Windows Sysinternals tools that can help you locate the source of such errors. We'll walk through two examples, a message dialog box and an event log entry.

Message Dialog Boxes
For the first example scenario, locating the owner of an error message's dialog box, we can use Process Explorer. Process Explorer includes a tool that lets you find a Windows process. In the Process Explorer toolbar, this tool is represented by the crosshair icon, as Figure 1 shows.

To use this tool, left-click and hold the mouse down, drag the crosshair icon onto the dialog message (Figure 2A), and release the mouse button.

 

Doing so will highlight the process that owns in error, as Figure 2B shows.

 

Here we'll use a very simple example of an error opening a nonexistent file in Notepad. In this case, it's obvious where the error message came from and why. However, if this dialog box were to suddenly appear (from a system service, for example), the source would not be at all obvious based on the dialog's text.

Furthermore, in many cases you'll be able to use Process Explorer to examine the thread stacks of this process instance to locate the origin of the message box, as Figure 3 shows.

 

There may be other function names in the thread's call stack that will provide useful information.
 
Event Log Error Message
In this example, we'll be searching program files for an arbitrary string taken from an event log entry. We can do this in a very primitive way using Sysinternals strings.exe tool; however, let's use a trick or two to optimize the search. After all, searching every single file on a system drive would be time-consuming and use a lot of unnecessary resources.

To optimize the search, we'll perform a few tasks using the batch files shown in Figures 4A and 4B. Batch file syntax is outside the scope of this article, so I will only briefly comment on each line and what it does.

Binstr.bat, in Figure 4A, is a cmd.exe batch file that takes two arguments; the first is a directory name, and the second is the string to look for. It uses a for loop to single out only .exe and .dll files in the given directory and its subfolders. It passes each of these filenames to a second batch file along with the string message we are looking for.

Figure 4A: Binstr.bat enumerating all .exe and .dll files in a given directory and its subfolders

Binstr.bat
==============================


@for /r %1 %%X in (*.exe *.dll) do @%~dp0\binstr_func.bat "%%X" %2
@echo Scan finished... please see %~dp0binstr_output.txt

Binstr_func.bat, in Figure 4B, can be thought of as a subroutine for the main batch file. This must be in a second file due to limitations in the batch for command syntax.

Figure 4B: Binstr_func.bat, a subroutine that calls strings.exe, filters its output, and logs results to file

Binstr_func.bat
==============================
@echo %1
@echo %1 >> %~dp0\binstr_output.txt
@%~dp0\strings.exe -o -q %1 | find.exe /i %2 >> %~dp0\binstr_output.txt

This subroutine takes two arguments: a filename and a string we are looking for. It then does three things. First, it prints the filename to the console to indicate that the batch file is progressing. Second, it logs the filename to a text file, binstr_output.txt. Finally, it calls strings.exe using the two given parameters and filters the output using find.exe, outputting the results to the text file.

Let's use an example to demonstrate usage and the output of the batch file. We'll take an event log entry, which Figure 5 shows, for which we already have a good idea of the source, as it's indicated in the message itself.

We can use this to verify that we did indeed find the correct message, using binstr.bat and binstr_output.txt, as Figures 6 and 7 show.

Figure 6: Using binstr.bat

C:\tmp>binstr.bat "c:\Program Files\Microsoft Office\" "Outlook detected a large number"
"c:\Program Files\Microsoft Office\Live Meeting 8\Addins\LMAddins.dll"
"c:\Program Files\Microsoft Office\Live Meeting 8\Addins\DA\LMIntSat.dll"

Scan finished... please see c:\tmp\binstr_output.txt

Figure 7: binstr_output.txt


"c:\Program Files\Microsoft Office\Office14\1033\IPOLKINTL.DLL"
"c:\Program Files\Microsoft Office\Office14\1033\MAPIR.DLL"
1099256:Outlook detected a large number of consecutive deletes (%1) from folder '%2'.
"c:\Program Files\Microsoft Office\Office14\1033\MAPISHELLR.DLL"
"c:\Program Files\Microsoft Office\Office14\1033\MOR6INT.DLL"

Demystified Errors
Error messages can sometimes be vague, and their source can be a mystery. The two techniques demonstrated in this article are by no means the only ways to help track down the source of mysterious error messages. But they should give you some insight into a few techniques and tools that can help you make progress on root cause analysis when you may otherwise feel like you're at a dead end.

Special thanks to Chris Carr, a Microsoft senior escalation engineer, who significantly contributed to this article.