Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save STDOUT outputs to a text file?

Tags:

c#

text

stdout

I have a program which utilizes a 3rd party command line tool to generate logs. The 3rd party generates all its output to the STDOUT which the user must then use the " > test.txt" command to save the file.

However the program somehow generates a certain amount of report generated but not the entire report. This was test by using the command

C:\Test\ftk\ripxp>ripxp.exe -r C:\test\ftk\ntuser.dat -d "C:\System Volume\_rest ore{BB12863B-2C77-46C9-BCDA-1810E52F1089}" -p runmru > C:\test\test05.txt

on the command line console which works and on the program which works only partially.

The errors were narrowed down to either the arguments error or the file saving error part (streamReader). Therefore the error could be due to the STDOUT not being properly saved.

Therefore may someone please advise on the codes? Thanks!

The Arguments for the 3rd party tool(2008 H. Carvey):

RipXP v.20081001 - CLI RegRipper tool
RipXP [-r Reg hive file] [-p plugin module][-d RP dir][-lgh]
Parse Windows Registry files, using either a single module from the plugins folder.
Then parse all corresponding hive files from the XP Restore Points (extracted from
image) using the same plugin.

-r Reg hive file...Registry hive file to parse
-g ................Guess the hive file (experimental)
-d RP directory....Path to the Restore Point directory
-p plugin module...use only this module
-l ................list all plugins
-h.................Help (print this information)

Ex: C:\>rip -g
C:\>rip -r d:\cases\ntuser.dat -d d:\cases\svi -p userassist

All output goes to STDOUT; use redirection (ie, > or >>) to output to a file.

copyright 2008 H. Carvey

The Codes:

static void Main(string[] args)
    {
        // Automatically finds folder that starts with _restore
        DirectoryInfo directoryInfo = new DirectoryInfo(@"C:\System Volume\");
        DirectoryInfo restoreFolder = directoryInfo.GetDirectories().FirstOrDefault(d => d.Name.StartsWith("_restore"));

        // Gets the folder name
        String baka = restoreFolder.Name;

        if (restoreFolder == null)
            throw new DirectoryNotFoundException();

            Process process = new Process();
            process.StartInfo.FileName = @"C:\test\ftk\ripxp\ripxp.exe";
            process.StartInfo.Arguments = @"-r C:\test\ftk\ntuser.dat -d C:\System Volume\" + restoreFolder.Name + " -p runmru";
            process.StartInfo.CreateNoWindow = false;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardInput = true;
            process.StartInfo.RedirectStandardError = true;
            process.Start();

            String text = @"-r C:\test\ftk\ntuser.dat -d C:\System Volume\" +restoreFolder.Name  + " -p runmru";
            Console.WriteLine(baka);
            Console.WriteLine(text);

            // Strangely the program only outputs the first section "-r C:\test\ftk\ntuser.dat" argument results.....
            System.IO.StreamReader reader = process.StandardOutput;
            String sRes = reader.ReadToEnd();
            StreamWriter SW;
            SW = File.CreateText(@"C:\test\test01.txt");
            SW.WriteLine(sRes);
            SW.Close();
            Console.WriteLine("File Created Successfully");
            reader.Close();

    }
like image 474
JavaNoob Avatar asked Dec 22 '22 20:12

JavaNoob


2 Answers

Are you waiting for the child process to finish? It looks like you start reading its output too early. It could be done like this:

process.Start();
process.WaitForExit();

Also, you can start receiving the output via delegates before it finishes. Like this (the delegate is called for each line of text):

process.OutputDataReceived += delegate(object sender, DataReceivedEventArgs e)
{
    // Store e.Data somewhere.
};
like image 189
detunized Avatar answered Jan 05 '23 15:01

detunized


You can have .NET inform you when the process has exited and then read the output. Because, as detunized mentioned in his answer+comment, if you call reader.ReadToEnd() before it has completed, you won't get all the output. If you think of it, it's quite obvious - the data hasn't been produced yet, so how can you expect the reader to read it?

By using events you will not block the method that starts the thread which can be quite useful if you have a GUI application and don't want to freeze the user interface while the child process is running.

// tell it to raise events and hook up a callback to when it completes
process.EnableRaisingEvents = true;
process.Exited += process_Exited;
process.Start();

This method will be called when the process has completed:

void process_Exited(object sender, EventArgs e)
{
    var process = (Process)sender;
    using (var f = File.CreateText(@"..."))
    {
        f.WriteLine(process.StandardOutput.ReadToEnd());
    }
}
like image 31
Isak Savo Avatar answered Jan 05 '23 17:01

Isak Savo