Note that there are some explanatory texts on larger screens.

plurals
  1. POHow Do I Redirect Output From Powershell
    primarykey
    data
    text
    <p>I have a similar, but different, question like <a href="https://stackoverflow.com/questions/4499182/how-to-redirect-powershell-output-from-a-script-run-by-taskscheduler-and-overrid">How to redirect Powershell output from a script run by TaskScheduler and override default width of 80 characters</a>.</p> <p>I have a custom installer framework written long ago. Within it I can execute "tasks". I recently had to add a task to execute a PowerShell script. Now, even though the task is written in C#, I cannot invoke the commands in the PowerShell script directly. That, unfortunately, is off the table. </p> <p>In short, I want to invoke a PowerShell executable from C# and redirect its output back to my application. Here's what I've done so far:</p> <p>I can successfully invoke PowerShell using the following code (from a test project I created):</p> <pre><code> string powerShellExeLocation = null; RegistryKey localKey = Registry.LocalMachine; RegistryKey subKey = localKey.OpenSubKey(@"SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine"); powerShellExeLocation = subKey.GetValue("ApplicationBase").ToString(); if (!Directory.Exists(powerShellExeLocation)) throw new Exception("Cannot locate the PowerShell dir."); powerShellExeLocation = Path.Combine(powerShellExeLocation, "powershell.exe"); if (!File.Exists(powerShellExeLocation)) throw new Exception("Cannot locate the PowerShell executable."); string scriptLocation = Path.Combine(Environment.CurrentDirectory, "PowerShellScript.ps1"); if (!File.Exists(scriptLocation)) throw new Exception("Cannot locate the PowerShell script."); ProcessStartInfo processInfo = new ProcessStartInfo(); processInfo.Verb = "runas"; processInfo.UseShellExecute = false; processInfo.RedirectStandardOutput = true; processInfo.RedirectStandardOutput = true; processInfo.WorkingDirectory = Environment.CurrentDirectory; processInfo.FileName = powerShellExeLocation; processInfo.Arguments = "-NoLogo -OutputFormat Text -NonInteractive -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + scriptLocation + "\" "; Process powerShellProcess = new Process(); powerShellProcess.StartInfo = processInfo; powerShellProcess.OutputDataReceived += new DataReceivedEventHandler(powerShellProcess_OutputDataReceived); powerShellProcess.ErrorDataReceived += new DataReceivedEventHandler(powerShellProcess_ErrorDataReceived); powerShellProcess.Start(); while (!powerShellProcess.HasExited) { Thread.Sleep(500); } </code></pre> <p>My handlers for the redirected output are never called:</p> <pre><code>void powerShellProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e) </code></pre> <p>and </p> <pre><code>void powerShellProcess_OutputDataReceived(object sender, DataReceivedEventArgs e) </code></pre> <p>I am fairly confident that the script is running. Right now I just have a test script that is outputting the PATH contents.</p> <pre><code>$a = $env:path; $a.Split(";") </code></pre> <p>I tested this from within a PowerShell instance and it outputs correctly.</p> <p>What can I do to get the PowerShell output to redirect to my C# code? I don't want to rely on the scripts that I will execute to handle their own logging. I'd rather gather their output and handle it within the framework's logging mechanism.</p> <p><strong>EDIT</strong> Realized I left the odd loop thing to wait for exit in that code example. I've had the process "WaitForExit":</p> <pre><code>powerShellProcess.WaitForExit(); </code></pre> <p><strong>EDIT</strong><br /> Using the suggestion from @MiniBill. I came up with the following code snippit:</p> <pre><code>powerShellProcess.Start(); while (!powerShellProcess.HasExited) { string line; while (!string.IsNullOrEmpty((line = powerShellProcess.StandardOutput.ReadLine()))) this.LogInfo("PowerShell running: " + line); } </code></pre> <p>This handles the output fine. It's cutting my lines at 80 characters :(, but I can live with that unless someone else can provide a suggestion to fix that!</p> <p><strong>UPDATE <em>A Solution</em></strong></p> <pre><code>/* * The next few lines define the process start info for the PowerShell executable. */ ProcessStartInfo processInfo = new ProcessStartInfo(); processInfo.Verb = "runas"; processInfo.UseShellExecute = false; processInfo.RedirectStandardError = true; processInfo.RedirectStandardOutput = true; processInfo.WorkingDirectory = Environment.CurrentDirectory; //this FileName was retrieved earlier by looking in the registry for key "HKLM\SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine" and the value for "ApplicationBase" processInfo.FileName = powerShellExeLocation; //if we're going to use script arguments build up the arguments from the process start correctly. if (!string.IsNullOrEmpty(this.ScriptArguments)) processInfo.Arguments = "-NoLogo -NonInteractive -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + ScriptLocation + "\" '" + ScriptArguments + "'"; else processInfo.Arguments = "-NoLogo -NonInteractive -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + ScriptLocation + "\""; //create the Process object, set the start info, and start the process Process powerShellProcess = new Process(); powerShellProcess.StartInfo = processInfo; powerShellProcess.Start(); /* * While the PowerShell process hasn't exited do the following: * * Read from the current position of the StandardOutput to the end by each line and * update the tasks progress with this information * * Read from the current position of StandardError to the end by each line, update * the task's progress with this information and set that we have an error. * * Sleep for 250 milliseconds (1/4 of a sec) */ bool isError = false; while (!powerShellProcess.HasExited) { string standardOuputLine, standardErrorLine; while (!string.IsNullOrEmpty((standardOuputLine = powerShellProcess.StandardOutput.ReadLine()))) { this.UpdateTaskProgress(standardOuputLine); } while (!string.IsNullOrEmpty((standardErrorLine = powerShellProcess.StandardError.ReadLine()))) { this.UpdateTaskProgress(standardErrorLine); isError = true; } Thread.Sleep(250); } /* * Now that the process has completed read to the end of StandardOutput and StandardError. * Update the task progress with this information. */ string finalStdOuputLine = powerShellProcess.StandardOutput.ReadToEnd(); string finalStdErrorLine = powerShellProcess.StandardError.ReadToEnd(); if (!string.IsNullOrEmpty(finalStdOuputLine)) this.UpdateTaskProgress(finalStdOuputLine); if (!string.IsNullOrEmpty(finalStdErrorLine)) { this.UpdateTaskProgress(finalStdErrorLine); isError = true; } // there was an error during the run of PowerShell that was output to StandardError. This doesn't necessarily mean that // the script error'd but there was a problem. Throw an exception for this. if (isError) throw new Exception(string.Format(CultureInfo.InvariantCulture, "Error during the execution of {0}.", this.ScriptLocation)); </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload