public virtual int Execute(ProcessStartInfo startInfo, CancellationToken cancellationToken, out string stdOut) { var outBuffer = new StringBuilder(); cancellationToken.ThrowIfCancellationRequested(); var process = Process.Start(startInfo); if (process == null) { throw PluginException.CreateNotStartedMessage(Path); } process.OutputDataReceived += (object o, DataReceivedEventArgs e) => { outBuffer.AppendLine(e.Data); }; // Trace and error information may be written to standard error by the provider. // It should be logged at the Information level so it will appear if Verbosity >= Normal. process.ErrorDataReceived += (object o, DataReceivedEventArgs e) => { if (!string.IsNullOrWhiteSpace(e?.Data)) { // This is a workaround for mono issue: https://github.com/NuGet/Home/issues/4004 if (!process.HasExited) { _logger.LogInformation($"{process.ProcessName}: {e.Data}"); } } }; process.BeginOutputReadLine(); process.BeginErrorReadLine(); using (cancellationToken.Register(() => Kill(process))) { if (!process.WaitForExit(TimeoutSeconds * 1000)) { Kill(process); throw PluginException.CreateTimeoutMessage(Path, TimeoutSeconds); } // Give time for the Async event handlers to finish by calling WaitForExit again. // if the first one succeeded // Note: Read remarks from https://msdn.microsoft.com/en-us/library/ty0d8k56(v=vs.110).aspx // for reason. process.WaitForExit(); } process.CancelErrorRead(); process.CancelOutputRead(); cancellationToken.ThrowIfCancellationRequested(); stdOut = outBuffer.ToString(); return(process.ExitCode); }