none
Trying to run a PS1 script through C# and capture output RRS feed

  • Question

  • I have been working on converting a GUI script from another language to C# in VS2017 for a customer. I am 95% of the way there, but have run into a couple of snags; just not sure I am doing things in the best way. I'm including just the relevant portions of code below, please let me know if I am not providing enough:

    The majority of the code is centered on the wpf form, which collects data for low level technicians to batch deploy a number of Virtual Machines into the VMware environment. This number could easily range into the dozens or even a hundred VMs at once. The information for each VM is specified in the form, then collected in a listview. Once the listview is fully populated it is exported to a csv. Up to this point everything works just fine.

    I've next been working on actually launching the powershell/powerCLI script and capturing output. The log file is opened with a specific reader application the customer uses, which updates in real time, and the captured output is fed to the log. It is important for the technicians to see the output from the code line by line so they can react if there is an issue.

    I started with something like this as a test:

    string sPSScript = "C:\\Users\\Admin\\Desktop\\TestC#.ps1"; string logFile = "C:\\Users\\Admin\\Desktop\\My.log"; string logReader = "C:\\Users\\Admin\\Documents\\CMTrace.exe"; string standard_output; System.Diagnostics.Process PSScript = new System.Diagnostics.Process(); PSScript.StartInfo.FileName = Environment.GetFolderPath(Environment.SpecialFolder.SystemX86) + "\\WindowsPowerShell\\v1.0\\powershell.exe"; PSScript.StartInfo.Arguments = "-command . '" + sPSScript + "' " + vCenter.Text; PSScript.StartInfo.RedirectStandardOutput = true; PSScript.StartInfo.UseShellExecute = false; PSScript.Start();

        System.Diagnostics.Process LogFile = new System.Diagnostics.Process();
        LogFile.StartInfo.FileName = logReader;
        LogFile.StartInfo.Arguments = logFile;
        LogFile.Start();

        while ((standard_output = PSScript.StandardOutput.ReadLine()) != null)
            {
               if (standard_output != "")
            {
              using (StreamWriter file = new StreamWriter(logFile, append: true))
              {
              file.WriteLine(standard_output);
                }
            }
           }

    While this writes to the log file in real time as expected, it creates 100 instances of the logReader application. I understand why, since I am declaring a new StreamWriter object through every pass. What I am unsure of is how best to write this section. I tried creating the file outside the loop, like this:

                    StreamWriter file = new StreamWriter(logFile, append: true) { };
    
                    System.Diagnostics.Process LogFile = new System.Diagnostics.Process();
                        LogFile.StartInfo.FileName = logReader;
                        LogFile.StartInfo.Arguments = logFile;
                    
                    System.Diagnostics.Process PSScript = new System.Diagnostics.Process();
                        PSScript.StartInfo.FileName = Environment.GetFolderPath(Environment.SpecialFolder.SystemX86) + "\\WindowsPowerShell\\v1.0\\powershell.exe";
                        PSScript.StartInfo.Arguments = "-command . '" + sPSScript + "' " + vCenter.Text;
                        PSScript.StartInfo.RedirectStandardOutput = true;
                        PSScript.StartInfo.UseShellExecute = false;
    
                        LogFile.Start();
                        PSScript.Start();
                    System.Threading.Thread.Sleep(1500);
    
                    while ((standard_output = PSScript.StandardOutput.ReadLine()) != null)
                    {
                        if (standard_output != "")
                        {
                            file.WriteLine(standard_output);
                        }
                    }

    It doesn't create multiple instances, but it also does not update the log file in real time as the previous code does. It only updates once the script runs, and then only partially. The script produces ~1000 lines of output, and I consistently see only about 840 written to the log file.

    I thought about doing something like this:

    FileStream logFS;
    logFS = new FileStream(logFile, FileMode.Append);

    but it appears the only options available to me to write to the file are expecting a byte array. 

    I am sure that I am missing something stupid simple in this, but would appreciate any suggestions on the easiest way to create the log file, open it in the reader, and then update it with the standard output from the powershell script.

    Thursday, December 28, 2017 4:57 PM

Answers

  • Answered my own question - I needed to add file.Flush(); as well as a short sleep after every write in the second code.
    • Marked as answer by JeremiahLogan Thursday, December 28, 2017 7:31 PM
    Thursday, December 28, 2017 7:31 PM