I recently ran into a situation where my test code was failing only under certain types of test pass runs on machines that I have no access to. To diagnose the problem, I wanted to log the contents of the filesystem under certain directories.
I was already familiar with System.Diagnostics.Process and System.Diagnostics.ProcessStartInfo, which exist to let you launch processes from your .Net program. In fact, the problem was that I was attempting to launch an executable using these classes, but the executable file wasn't being found. I struggled for over an hour with trying to run 'dir /s', the command for recursively listing the contents of a folder and all subfolders, using the Process class. Eventually, I worked out one solution, shown in the C# fragment below, that allows me to run the command and grab the output into a string.
/// Outputs recursively the contents of the specified path to
/// the test log.
/// <param name="path">The path to list contents from.</param>
private static void LogRecursiveDirectoryContents(string path)
string batchFile = Path.ChangeExtension(Path.GetTempFileName(),".bat");
string commands = "dir /s" + Environment.NewLine;
ProcessStartInfo batchInfo = new ProcessStartInfo(batchFile);
batchInfo.UseShellExecute = false;
batchInfo.RedirectStandardOutput = true;
batchInfo.WorkingDirectory = path;
using (Process batchProcess = Process.Start(batchInfo))
As you can see, I used static methods in System.IO.Path and System.IO.File to generate a temporary batch file with my shell command as the contents. Then, I create a ProcessStartInfo object for running the batch file, setting 'UseShellExecute' to false and 'RedirectStandardOutput' to true. Setting these two properties will allow me to get the ouput of the batch file process from the Process's StandardOutput stream. The final step before launching the process is to set the 'WorkingDirectory' where the batch file will be executing from. In my case, I used the result of Environment.GetEnvironmentVariable("programfiles").
Finally, the process is launched in the context of a 'using' block, since Process uses native resources and needs to have Dispose() called on it in order to release them. I log the output using boilerplate code from the documentation of Process.StandardOutput and my test environment's logger.
I hope you found this useful and interesting.