CLI tool for running Playbooks
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
4.8 KiB

1 year ago
  1. using System;
  2. using System.Diagnostics;
  3. using System.IO;
  4. using System.Threading.Tasks;
  5. using TrustedUninstaller.Shared.Exceptions;
  6. using TrustedUninstaller.Shared.Tasks;
  7. using YamlDotNet.Serialization;
  8. namespace TrustedUninstaller.Shared.Actions
  9. {
  10. public class CmdAction : ITaskAction
  11. {
  12. [YamlMember(typeof(string), Alias = "command")]
  13. public string Command { get; set; }
  14. [YamlMember(typeof(string), Alias = "timeout")]
  15. public int? Timeout { get; set; }
  16. [YamlMember(typeof(string), Alias = "wait")]
  17. public bool Wait { get; set; } = true;
  18. [YamlMember(typeof(bool), Alias = "exeDir")]
  19. public bool ExeDir { get; set; } = false;
  20. [YamlMember(typeof(string), Alias = "weight")]
  21. public int ProgressWeight { get; set; } = 1;
  22. public int GetProgressWeight() => ProgressWeight;
  23. private bool InProgress { get; set; }
  24. public void ResetProgress() => InProgress = false;
  25. private int? ExitCode { get; set; }
  26. public string? StandardError { get; set; }
  27. public string StandardOutput { get; set; }
  28. public string ErrorString() => $"CmdAction failed to run command '{Command}'.";
  29. public UninstallTaskStatus GetStatus()
  30. {
  31. if (InProgress)
  32. {
  33. return UninstallTaskStatus.InProgress;
  34. }
  35. return ExitCode == null ? UninstallTaskStatus.ToDo: UninstallTaskStatus.Completed;
  36. }
  37. public async Task<bool> RunTask()
  38. {
  39. if (InProgress) throw new TaskInProgressException("Another Cmd action was called while one was in progress.");
  40. InProgress = true;
  41. Console.WriteLine($"Running cmd command '{Command}'...");
  42. ExitCode = null;
  43. var process = new Process();
  44. var startInfo = new ProcessStartInfo
  45. {
  46. WindowStyle = ProcessWindowStyle.Normal,
  47. FileName = "cmd.exe",
  48. Arguments = "/C " + $"\"{Environment.ExpandEnvironmentVariables(this.Command)}\"",
  49. UseShellExecute = false,
  50. RedirectStandardError = true,
  51. RedirectStandardOutput = true,
  52. CreateNoWindow = true
  53. };
  54. if (ExeDir) startInfo.WorkingDirectory = AmeliorationUtil.Playbook.Path + "\\Executables";
  55. if (!Wait)
  56. {
  57. startInfo.RedirectStandardError = false;
  58. startInfo.RedirectStandardOutput = false;
  59. startInfo.WindowStyle = ProcessWindowStyle.Hidden;
  60. startInfo.UseShellExecute = true;
  61. }
  62. process.StartInfo = startInfo;
  63. process.Start();
  64. if (!Wait)
  65. {
  66. process.Dispose();
  67. return true;
  68. }
  69. process.OutputDataReceived += ProcOutputHandler;
  70. process.BeginOutputReadLine();
  71. if (Timeout != null)
  72. {
  73. var exited = process.WaitForExit(Timeout.Value);
  74. if (!exited)
  75. {
  76. process.Kill();
  77. throw new TimeoutException($"Command '{Command}' timeout exceeded.");
  78. }
  79. }
  80. else process.WaitForExit();
  81. if (process.ExitCode != 0)
  82. {
  83. StandardError = process.StandardError.ReadToEnd();
  84. Console.WriteLine($"cmd instance exited with error code: {process.ExitCode}");
  85. if (!String.IsNullOrEmpty(StandardError)) Console.WriteLine($"Error message: {StandardError}");
  86. ErrorLogger.WriteToErrorLog("Cmd exited with a non-zero exit code: " + process.ExitCode, null, "CmdAction Error", Command);
  87. this.ExitCode = process.ExitCode;
  88. }
  89. else
  90. {
  91. ExitCode = 0;
  92. }
  93. process.CancelOutputRead();
  94. process.Dispose();
  95. InProgress = false;
  96. return true;
  97. }
  98. private static void ProcOutputHandler(object sendingProcess,
  99. DataReceivedEventArgs outLine)
  100. {
  101. var outputString = outLine.Data;
  102. // Collect the sort command output.
  103. if (!String.IsNullOrEmpty(outLine.Data))
  104. {
  105. if (outputString.Contains("\\AME"))
  106. {
  107. outputString = outputString.Substring(outputString.IndexOf('>') + 1);
  108. }
  109. Console.WriteLine(outputString);
  110. }
  111. else
  112. {
  113. Console.WriteLine();
  114. }
  115. }
  116. }
  117. }