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<bool> 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();
|
|
}
|
|
}
|
|
}
|
|
}
|