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.

134 lines
4.5 KiB

1 year ago
  1. using System;
  2. using System.Linq;
  3. using System.Threading.Tasks;
  4. using Windows.ApplicationModel;
  5. using Windows.Management.Deployment;
  6. using TrustedUninstaller.Shared.Exceptions;
  7. using TrustedUninstaller.Shared.Tasks;
  8. using YamlDotNet.Serialization;
  9. using System.Diagnostics;
  10. using System.IO;
  11. using System.Text;
  12. using System.Threading;
  13. namespace TrustedUninstaller.Shared.Actions
  14. {
  15. // Integrate ame-assassin later
  16. internal class AppxAction : ITaskAction
  17. {
  18. public enum AppxOperation
  19. {
  20. Remove = 0,
  21. ClearCache = 1,
  22. }
  23. public enum Level
  24. {
  25. Family = 0,
  26. Package = 1,
  27. App = 2
  28. }
  29. [YamlMember(typeof(string), Alias = "name")]
  30. public string Name { get; set; }
  31. [YamlMember(typeof(Level), Alias = "type")]
  32. public Level? Type { get; set; } = Level.Family;
  33. [YamlMember(typeof(AppxOperation), Alias = "operation")]
  34. public AppxOperation Operation { get; set; } = AppxOperation.Remove;
  35. [YamlMember(typeof(bool), Alias = "verboseOutput")]
  36. public bool Verbose { get; set; } = false;
  37. [YamlMember(typeof(string), Alias = "weight")]
  38. public int ProgressWeight { get; set; } = 30;
  39. public int GetProgressWeight() => ProgressWeight;
  40. private bool InProgress { get; set; }
  41. public void ResetProgress() => InProgress = false;
  42. public string ErrorString() => $"AppxAction failed to remove '{Name}'.";
  43. private Package GetPackage()
  44. {
  45. var packageManager = new PackageManager();
  46. return packageManager.FindPackages().FirstOrDefault(package => package.Id.Name == Name);
  47. }
  48. public UninstallTaskStatus GetStatus()
  49. {
  50. if (InProgress) return UninstallTaskStatus.InProgress;
  51. return HasFinished ? UninstallTaskStatus.Completed : UninstallTaskStatus.ToDo;
  52. //return GetPackage() == null ? UninstallTaskStatus.Completed : UninstallTaskStatus.ToDo;
  53. }
  54. private bool HasFinished = false;
  55. public async Task<bool> RunTask()
  56. {
  57. if (InProgress) throw new TaskInProgressException("Another Appx action was called while one was in progress.");
  58. InProgress = true;
  59. Console.WriteLine($"Removing APPX {Type.ToString().ToLower()} '{Name}'...");
  60. string verboseArg = Verbose ? " -Verbose" : "";
  61. var psi = new ProcessStartInfo()
  62. {
  63. UseShellExecute = false,
  64. CreateNoWindow = true,
  65. Arguments = $@"-{Type.ToString()} ""{Name}""" + verboseArg,
  66. FileName = Directory.GetCurrentDirectory() + "\\ame-assassin\\ame-assassin.exe",
  67. RedirectStandardOutput = true,
  68. RedirectStandardError = true
  69. };
  70. if (Operation == AppxOperation.ClearCache)
  71. {
  72. psi.Arguments = $@"-ClearCache ""{Name}""";
  73. }
  74. var proc = Process.Start(psi);
  75. proc.OutputDataReceived += ProcOutputHandler;
  76. proc.ErrorDataReceived += ProcOutputHandler;
  77. proc.BeginOutputReadLine();
  78. proc.BeginErrorReadLine();
  79. bool exited = proc.WaitForExit(30000);
  80. // WaitForExit alone seems to not be entirely reliable
  81. while (!exited && ExeRunning(proc))
  82. {
  83. exited = proc.WaitForExit(30000);
  84. }
  85. using (var log = new StreamWriter("Logs\\Packages.txt", true))
  86. log.Write(output.ToString());
  87. HasFinished = true;
  88. InProgress = false;
  89. return true;
  90. }
  91. private StringBuilder output = new StringBuilder("");
  92. private void ProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
  93. {
  94. var write = outLine.Data == null ? "" : outLine.Data;
  95. output.Append(write + Environment.NewLine);
  96. if (!write.Equals("Complete!")) Console.WriteLine(write);
  97. }
  98. private static bool ExeRunning(Process process)
  99. {
  100. try
  101. {
  102. return Process.GetProcessesByName(process.ProcessName).Any(x => x.Id == process.Id);
  103. }
  104. catch (Exception)
  105. {
  106. return false;
  107. }
  108. }
  109. }
  110. }