using System; using System.Diagnostics; using System.IO; using System.Threading.Tasks; using TrustedUninstaller.Shared.Exceptions; using TrustedUninstaller.Shared.Tasks; using YamlDotNet.Serialization; namespace TrustedUninstaller.Shared.Actions { public class CmdAction : ITaskAction { [YamlMember(typeof(string), Alias = "command")] public string Command { get; set; } [YamlMember(typeof(string), Alias = "timeout")] public int? Timeout { get; set; } [YamlMember(typeof(string), Alias = "wait")] public bool Wait { get; set; } = true; [YamlMember(typeof(bool), Alias = "exeDir")] public bool ExeDir { get; set; } = false; [YamlMember(typeof(string), Alias = "weight")] public int ProgressWeight { get; set; } = 1; public int GetProgressWeight() => ProgressWeight; private bool InProgress { get; set; } public void ResetProgress() => InProgress = false; private int? ExitCode { get; set; } public string? StandardError { get; set; } public string StandardOutput { get; set; } public string ErrorString() => $"CmdAction failed to run command '{Command}'."; public UninstallTaskStatus GetStatus() { if (InProgress) { return UninstallTaskStatus.InProgress; } return ExitCode == null ? UninstallTaskStatus.ToDo: UninstallTaskStatus.Completed; } public async Task RunTask() { if (InProgress) throw new TaskInProgressException("Another Cmd action was called while one was in progress."); InProgress = true; Console.WriteLine($"Running cmd command '{Command}'..."); ExitCode = null; var process = new Process(); var startInfo = new ProcessStartInfo { WindowStyle = ProcessWindowStyle.Normal, FileName = "cmd.exe", Arguments = "/C " + $"\"{Environment.ExpandEnvironmentVariables(this.Command)}\"", UseShellExecute = false, RedirectStandardError = true, RedirectStandardOutput = true, CreateNoWindow = true }; if (ExeDir) startInfo.WorkingDirectory = AmeliorationUtil.Playbook.Path + "\\Executables"; if (!Wait) { startInfo.RedirectStandardError = false; startInfo.RedirectStandardOutput = false; startInfo.WindowStyle = ProcessWindowStyle.Hidden; startInfo.UseShellExecute = true; } process.StartInfo = startInfo; process.Start(); if (!Wait) { process.Dispose(); return true; } process.OutputDataReceived += ProcOutputHandler; process.BeginOutputReadLine(); if (Timeout != null) { var exited = process.WaitForExit(Timeout.Value); if (!exited) { process.Kill(); throw new TimeoutException($"Command '{Command}' timeout exceeded."); } } else process.WaitForExit(); if (process.ExitCode != 0) { StandardError = process.StandardError.ReadToEnd(); Console.WriteLine($"cmd instance exited with error code: {process.ExitCode}"); if (!String.IsNullOrEmpty(StandardError)) Console.WriteLine($"Error message: {StandardError}"); ErrorLogger.WriteToErrorLog("Cmd exited with a non-zero exit code: " + process.ExitCode, null, "CmdAction Error", Command); this.ExitCode = process.ExitCode; } else { ExitCode = 0; } process.CancelOutputRead(); process.Dispose(); InProgress = false; return true; } private static void ProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) { var outputString = outLine.Data; // Collect the sort command output. if (!String.IsNullOrEmpty(outLine.Data)) { if (outputString.Contains("\\AME")) { outputString = outputString.Substring(outputString.IndexOf('>') + 1); } Console.WriteLine(outputString); } else { Console.WriteLine(); } } } }