简体   繁体   中英

Capturing output from powershell script

I have been working on converting a GUI script from another language to C# in VS2017 for a customer. With help from the folks here 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 (also working) 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, but am unsure how better to go about this.

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.

why did the previous code writes in real time?

because you are wrapping it with using . And at the end of using block its gonna call dispose which calls .Flush to write to disk

Your second code block calls WriteLine but never called Flush so it writes to the disk whenever the buffer is full. Just add a .Flush call after WriteLine and you will have real time logging

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM