private ProcessOutput(Process process, Redirector redirector) { _arguments = QuoteSingleArgument(process.StartInfo.FileName) + " " + process.StartInfo.Arguments; _redirector = redirector; if (_redirector == null) { _output = new List <string>(); _error = new List <string>(); _redirector = new ListRedirector(_output, _error); } _process = process; if (_process.StartInfo.RedirectStandardOutput) { _process.OutputDataReceived += OnOutputDataReceived; } if (_process.StartInfo.RedirectStandardError) { _process.ErrorDataReceived += OnErrorDataReceived; } if (!_process.StartInfo.RedirectStandardOutput && !_process.StartInfo.RedirectStandardError) { // If we are receiving output events, we signal that the process // has exited when one of them receives null. Otherwise, we have // to listen for the Exited event. // If we just listen for the Exited event, we may receive it // before all the output has arrived. _process.Exited += OnExited; } _process.EnableRaisingEvents = true; try { _process.Start(); } catch (Win32Exception ex) { _redirector.WriteErrorLine(ex.Message); _process = null; } catch (Exception ex) when(!ex.IsCriticalException()) { foreach (var line in SplitLines(ex.ToString())) { _redirector.WriteErrorLine(line); } _process = null; } if (_process != null) { if (_process.StartInfo.RedirectStandardOutput) { _process.BeginOutputReadLine(); } if (_process.StartInfo.RedirectStandardError) { _process.BeginErrorReadLine(); } if (_process.StartInfo.RedirectStandardInput) { // Close standard input so that we don't get stuck trying to read input from the user. try { _process.StandardInput.Close(); } catch (InvalidOperationException) { // StandardInput not available } } } }
/// <summary> /// Runs the file with the provided settings as a user with /// administrative permissions. The window is always hidden and output /// is provided to the redirector when the process terminates. /// </summary> /// <param name="filename">Executable file to run.</param> /// <param name="arguments">Arguments to pass.</param> /// <param name="workingDirectory">Starting directory.</param> /// <param name="redirector"> /// An object to receive redirected output. /// </param> /// <param name="quoteArgs"></param> /// <returns>A <see cref="ProcessOutput"/> object.</returns> public static ProcessOutput RunElevated( string filename, IEnumerable<string> arguments, string workingDirectory, IEnumerable<KeyValuePair<string, string>> env, Redirector redirector, bool quoteArgs = true, bool elevate = true, Encoding outputEncoding = null, Encoding errorEncoding = null ) { var psi = new ProcessStartInfo(PythonToolsInstallPath.GetFile("Microsoft.PythonTools.RunElevated.exe", typeof(ProcessOutput).Assembly)); psi.CreateNoWindow = true; psi.WindowStyle = ProcessWindowStyle.Hidden; psi.UseShellExecute = true; psi.Verb = elevate ? "runas" : null; int port = GetFreePort(); var listener = new TcpListener(IPAddress.Loopback, port); psi.Arguments = port.ToString(); var utf8 = new UTF8Encoding(false); // Send args and env as base64 to avoid newline issues string args; if (quoteArgs) { args = string.Join("|", arguments .Where(a => a != null) .Select(a => Convert.ToBase64String(utf8.GetBytes(QuoteSingleArgument(a)))) ); } else { args = string.Join("|", arguments .Where(a => a != null) .Select(a => Convert.ToBase64String(utf8.GetBytes(a))) ); } var fullEnv = env != null ? string.Join("|", env.Select(kv => kv.Key + "=" + Convert.ToBase64String(utf8.GetBytes(kv.Value)))) : ""; listener.Start(); listener.AcceptTcpClientAsync().ContinueWith(t => { listener.Stop(); var client = t.Result; using (var writer = new StreamWriter(client.GetStream(), utf8, 4096, true)) { writer.WriteLine(filename); writer.WriteLine(args); writer.WriteLine(workingDirectory); writer.WriteLine(fullEnv); writer.WriteLine(outputEncoding?.WebName ?? ""); writer.WriteLine(errorEncoding?.WebName ?? ""); } if (redirector != null) { var reader = new StreamReader(client.GetStream(), utf8, false, 4096, true); Task.Run(() => { try { for (var line = reader.ReadLine(); line != null; line = reader.ReadLine()) { if (line.StartsWith("OUT:")) { redirector.WriteLine(line.Substring(4)); } else if (line.StartsWith("ERR:")) { redirector.WriteErrorLine(line.Substring(4)); } else { redirector.WriteLine(line); } } } catch (IOException) { } catch (ObjectDisposedException) { } }); } }); var process = new Process(); process.StartInfo = psi; return new ProcessOutput(process, redirector); }
/// <summary> /// Runs the file with the provided settings as a user with /// administrative permissions. The window is always hidden and output /// is provided to the redirector when the process terminates. /// </summary> /// <param name="filename">Executable file to run.</param> /// <param name="arguments">Arguments to pass.</param> /// <param name="workingDirectory">Starting directory.</param> /// <param name="redirector"> /// An object to receive redirected output. /// </param> /// <param name="quoteArgs"></param> /// <returns>A <see cref="ProcessOutput"/> object.</returns> public static ProcessOutput RunElevated( string filename, IEnumerable <string> arguments, string workingDirectory, IEnumerable <KeyValuePair <string, string> > env, Redirector redirector, bool quoteArgs = true, bool elevate = true, Encoding outputEncoding = null, Encoding errorEncoding = null ) { var psi = new ProcessStartInfo(PythonToolsInstallPath.GetFile("Microsoft.PythonTools.RunElevated.exe", typeof(ProcessOutput).Assembly)); psi.CreateNoWindow = true; psi.WindowStyle = ProcessWindowStyle.Hidden; var utf8 = new UTF8Encoding(false); // Send args and env as base64 to avoid newline issues string args; if (quoteArgs) { args = string.Join("|", arguments .Where(a => a != null) .Select(a => Convert.ToBase64String(utf8.GetBytes(QuoteSingleArgument(a)))) ); } else { args = string.Join("|", arguments .Where(a => a != null) .Select(a => Convert.ToBase64String(utf8.GetBytes(a))) ); } var fullEnv = env != null? string.Join("|", env.Select(kv => kv.Key + "=" + Convert.ToBase64String(utf8.GetBytes(kv.Value)))) : ""; TcpListener listener = null; Task <TcpClient> clientTask = null; try { listener = SocketUtils.GetRandomPortListener(IPAddress.Loopback, out int port); psi.Arguments = port.ToString(); clientTask = listener.AcceptTcpClientAsync(); } catch (Exception ex) { listener?.Stop(); throw new InvalidOperationException(Strings.UnableToElevate, ex); } var process = new Process(); clientTask.ContinueWith(t => { listener.Stop(); TcpClient client; try { client = t.Result; } catch (AggregateException ae) { try { process.Kill(); } catch (InvalidOperationException) { } catch (Win32Exception) { } if (redirector != null) { foreach (var ex in ae.InnerExceptions.DefaultIfEmpty(ae)) { using (var reader = new StringReader(ex.ToString())) { for (var line = reader.ReadLine(); line != null; line = reader.ReadLine()) { redirector.WriteErrorLine(line); } } } } return; } using (var writer = new StreamWriter(client.GetStream(), utf8, 4096, true)) { writer.WriteLine(filename); writer.WriteLine(args); writer.WriteLine(workingDirectory); writer.WriteLine(fullEnv); writer.WriteLine(outputEncoding?.WebName ?? ""); writer.WriteLine(errorEncoding?.WebName ?? ""); } if (redirector != null) { var reader = new StreamReader(client.GetStream(), utf8, false, 4096, true); Task.Run(() => { try { for (var line = reader.ReadLine(); line != null; line = reader.ReadLine()) { if (line.StartsWithOrdinal("OUT:")) { redirector.WriteLine(line.Substring(4)); } else if (line.StartsWithOrdinal("ERR:")) { redirector.WriteErrorLine(line.Substring(4)); } else { redirector.WriteLine(line); } } } catch (IOException) { } catch (ObjectDisposedException) { } }); } }); process.StartInfo = psi; return(new ProcessOutput(process, redirector)); }
/// <summary> /// Runs the file with the provided settings as a user with /// administrative permissions. The window is always hidden and output /// is provided to the redirector when the process terminates. /// </summary> /// <param name="filename">Executable file to run.</param> /// <param name="arguments">Arguments to pass.</param> /// <param name="workingDirectory">Starting directory.</param> /// <param name="redirector"> /// An object to receive redirected output. /// </param> /// <param name="quoteArgs"></param> /// <returns>A <see cref="ProcessOutput"/> object.</returns> public static ProcessOutput RunElevated( string filename, IEnumerable <string> arguments, string workingDirectory, IEnumerable <KeyValuePair <string, string> > env, Redirector redirector, bool quoteArgs = true, bool elevate = true, Encoding outputEncoding = null, Encoding errorEncoding = null ) { var psi = new ProcessStartInfo(PythonToolsInstallPath.GetFile("Microsoft.PythonTools.RunElevated.exe", typeof(ProcessOutput).Assembly)); psi.CreateNoWindow = true; psi.WindowStyle = ProcessWindowStyle.Hidden; psi.UseShellExecute = true; psi.Verb = elevate ? "runas" : null; int port = GetFreePort(); var listener = new TcpListener(IPAddress.Loopback, port); psi.Arguments = port.ToString(); var utf8 = new UTF8Encoding(false); // Send args and env as base64 to avoid newline issues string args; if (quoteArgs) { args = string.Join("|", arguments .Where(a => a != null) .Select(a => Convert.ToBase64String(utf8.GetBytes(QuoteSingleArgument(a)))) ); } else { args = string.Join("|", arguments .Where(a => a != null) .Select(a => Convert.ToBase64String(utf8.GetBytes(a))) ); } var fullEnv = env != null? string.Join("|", env.Select(kv => kv.Key + "=" + Convert.ToBase64String(utf8.GetBytes(kv.Value)))) : ""; listener.Start(); listener.AcceptTcpClientAsync().ContinueWith(t => { listener.Stop(); var client = t.Result; using (var writer = new StreamWriter(client.GetStream(), utf8, 4096, true)) { writer.WriteLine(filename); writer.WriteLine(args); writer.WriteLine(workingDirectory); writer.WriteLine(fullEnv); writer.WriteLine(outputEncoding?.WebName ?? ""); writer.WriteLine(errorEncoding?.WebName ?? ""); } if (redirector != null) { var reader = new StreamReader(client.GetStream(), utf8, false, 4096, true); Task.Run(() => { try { for (var line = reader.ReadLine(); line != null; line = reader.ReadLine()) { if (line.StartsWith("OUT:")) { redirector.WriteLine(line.Substring(4)); } else if (line.StartsWith("ERR:")) { redirector.WriteErrorLine(line.Substring(4)); } else { redirector.WriteLine(line); } } } catch (IOException) { } catch (ObjectDisposedException) { } }); } }); var process = new Process(); process.StartInfo = psi; return(new ProcessOutput(process, redirector)); }