/// <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) { Task.Run(() => { using (var reader = new StreamReader(client.GetStream(), utf8, false, 4096, true)) { try { string line; while ((line = reader.ReadLine()) != null) { 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)); }