2

I'm creating a MVC4 web application that will have the ability to create a console that logs the output from a Powershell script to a log window using SignalR. Currently the best I have gotten to work is Capturing Powershell output in C# after Pipeline.Invoke throws. Problem is that I am not able to pass a live stream of output to the client using this method. I am only able to feed the output once the script is finished being processed. Currently i am trying this but am not receiving any output.

var loggingHub = new LoggingHub();

string powerShellExeLocation = null;

var localKey = Registry.LocalMachine;

var 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.");

if (!File.Exists(scriptFile))
    throw new Exception("Cannot locate the PowerShell script.");

var processInfo = new ProcessStartInfo
{
    Verb = "runas",
    UseShellExecute = false,
    RedirectStandardOutput = true
};
processInfo.RedirectStandardOutput = true;
processInfo.WorkingDirectory = Environment.CurrentDirectory;

processInfo.FileName = powerShellExeLocation;
//processInfo.Arguments = "-NoLogo -OutputFormat Text -NonInteractive -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + scriptFile + "\" ";
processInfo.Arguments = build;

var powerShellProcess = new Process {StartInfo = processInfo};

powerShellProcess.Start();

while (!powerShellProcess.HasExited)
{
    loggingHub.Send(DateTime.Now.ToString("h:mm:ss tt"), "info", powerShellProcess.StandardOutput.ReadLine());
}
Community
  • 1
  • 1
N00b1fied
  • 21
  • 3

2 Answers2

1

One way to log the output as it is happening is to not only host the PowerShell engine but to also implement the host interfaces. You will then get called back for every "write" to the "host" as the PowerShell engine processes the script. Implement the host interfaces isn't trivial but it's not too hard either. Take a look at this MSDN link http://msdn.microsoft.com/en-us/windows/desktop/ee706584(v=vs.85)

Keith Hill
  • 194,368
  • 42
  • 353
  • 369
1

From:

http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput(v=vs.110).aspx

**When a Process writes text to its standard stream, that text is typically displayed on the console. By redirecting the StandardOutput stream, you can manipulate or suppress the output of a process. For example, you can filter the text, format it differently, or write the output to both the console and a designated log file. Note You must set UseShellExecute to false if you want to set RedirectStandardOutput to true. Otherwise, reading from the StandardOutput stream throws an exception.

The redirected StandardOutput stream can be read synchronously or asynchronously. Methods such as Read, ReadLine, and ReadToEnd perform synchronous read operations on the output stream of the process. These synchronous read operations do not complete until the associated Process writes to its StandardOutput stream, or closes the stream. In contrast, BeginOutputReadLine starts asynchronous read operations on the StandardOutput stream. This method enables a designated event handler for the stream output and immediately returns to the caller, which can perform other work while the stream output is directed to the event handler. Note The application that is processing the asynchronous output should call the WaitForExit method to ensure that the output buffer has been flushed.

Synchronous read operations introduce a dependency between the caller reading from the StandardOutput stream and the child process writing to that stream. These dependencies can cause deadlock conditions. When the caller reads from the redirected stream of a child process, it is dependent on the child. The caller waits for the read operation until the child writes to the stream or closes the stream. When the child process writes enough data to fill its redirected stream, it is dependent on the parent. The child process waits for the next write operation until the parent reads from the full stream or closes the stream. The deadlock condition results when the caller and child process wait for each other to complete an operation, and neither can continue. You can avoid deadlocks by evaluating dependencies between the caller and child process.**

That seems to explain what's happening. Have you tried using the BeginOutputReadLine method instead of ReadLine?

mjolinor
  • 66,130
  • 7
  • 114
  • 135