I created a class to start the process, and it has grown in recent years due to different requirements. During use, I found several problems with the Process class with deleting and even reading ExitCode. It is processed by the class and is referred to as code comment.
The class has several capabilities, for example, reading output, running as an administrator or another user, catching exceptions, and also starting all this asynchronous on. Cancel It's nice that reading the results is also possible at runtime.
public class ProcessSettings { public string FileName { get; set; } public string Arguments { get; set; } = ""; public string WorkingDirectory { get; set; } = ""; public string InputText { get; set; } = null; public int Timeout_milliseconds { get; set; } = -1; public bool ReadOutput { get; set; } public bool ShowWindow { get; set; } public bool KeepWindowOpen { get; set; } public bool StartAsAdministrator { get; set; } public string StartAsUsername { get; set; } public string StartAsUsername_Password { get; set; } public string StartAsUsername_Domain { get; set; } public bool DontReadExitCode { get; set; } public CancellationToken CancellationToken { get; set; } } public class ProcessOutputReader // Optional, to get the output while executing instead only as result at the end { public event TextEventHandler OutputChanged; public event TextEventHandler OutputErrorChanged; public void UpdateOutput(string text) { OutputChanged?.Invoke(this, new TextEventArgs(text)); } public void UpdateOutputError(string text) { OutputErrorChanged?.Invoke(this, new TextEventArgs(text)); } public delegate void TextEventHandler(object sender, TextEventArgs e); public class TextEventArgs : EventArgs { public string Text { get; } public TextEventArgs(string text) { Text = text; } } } public class ProcessResult { public string Output { get; set; } public string OutputError { get; set; } public int ExitCode { get; set; } public bool WasCancelled { get; set; } public bool WasSuccessful { get; set; } } public class ProcessStarter { public ProcessResult Execute(ProcessSettings settings, ProcessOutputReader outputReader = null) { return Task.Run(() => ExecuteAsync(settings, outputReader)).GetAwaiter().GetResult(); } public async Task<ProcessResult> ExecuteAsync(ProcessSettings settings, ProcessOutputReader outputReader = null) { if (settings.FileName == null) throw new ArgumentNullException(nameof(ProcessSettings.FileName)); if (settings.Arguments == null) throw new ArgumentNullException(nameof(ProcessSettings.Arguments)); var cmdSwitches = "/Q " + (settings.KeepWindowOpen ? "/K" : "/C"); var arguments = $"{cmdSwitches} {settings.FileName} {settings.Arguments}"; var startInfo = new ProcessStartInfo("cmd", arguments) { UseShellExecute = false, RedirectStandardOutput = settings.ReadOutput, RedirectStandardError = settings.ReadOutput, RedirectStandardInput = settings.InputText != null, CreateNoWindow = !(settings.ShowWindow || settings.KeepWindowOpen), }; if (!string.IsNullOrWhiteSpace(settings.StartAsUsername)) { if (string.IsNullOrWhiteSpace(settings.StartAsUsername_Password)) throw new ArgumentNullException(nameof(ProcessSettings.StartAsUsername_Password)); if (string.IsNullOrWhiteSpace(settings.StartAsUsername_Domain)) throw new ArgumentNullException(nameof(ProcessSettings.StartAsUsername_Domain)); if (string.IsNullOrWhiteSpace(settings.WorkingDirectory)) settings.WorkingDirectory = Path.GetPathRoot(Path.GetTempPath()); startInfo.UserName = settings.StartAsUsername; startInfo.PasswordInClearText = settings.StartAsUsername_Password; startInfo.Domain = settings.StartAsUsername_Domain; } var output = new StringBuilder(); var error = new StringBuilder(); if (!settings.ReadOutput) { output.AppendLine($"Enable {nameof(ProcessSettings.ReadOutput)} to get Output"); } if (settings.StartAsAdministrator) { startInfo.Verb = "runas"; startInfo.UseShellExecute = true;
Apfelkuacha May 11 '19 at 14:18 2019-05-11 14:18
source share