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
5.0 KiB

1 year ago
  1. using System;
  2. using System.Linq;
  3. using System.Threading.Tasks;
  4. using TrustedUninstaller.Shared.Exceptions;
  5. using TrustedUninstaller.Shared.Tasks;
  6. using YamlDotNet.Serialization;
  7. using System.Diagnostics;
  8. using System.IO;
  9. using System.Text;
  10. using System.Threading;
  11. namespace TrustedUninstaller.Shared.Actions
  12. {
  13. internal class SystemPackageAction : ITaskAction
  14. {
  15. public enum Architecture
  16. {
  17. amd64 = 0,
  18. wow64 = 1,
  19. msil = 2,
  20. x86 = 3,
  21. All = 4
  22. }
  23. [YamlMember(typeof(string), Alias = "name")]
  24. public string Name { get; set; }
  25. [YamlMember(typeof(string), Alias = "arch")]
  26. public Architecture Arch { get; set; } = Architecture.All;
  27. [YamlMember(typeof(string), Alias = "language")]
  28. public string Language { get; set; } = "*";
  29. [YamlMember(typeof(string), Alias = "regexExcludeFiles")]
  30. public string[]? RegexExcludeList { get; set; }
  31. [YamlMember(typeof(string), Alias = "excludeDependents")]
  32. public string[]? ExcludeDependentsList { get; set; }
  33. [YamlMember(typeof(string[]), Alias = "weight")]
  34. public int ProgressWeight { get; set; } = 15;
  35. public int GetProgressWeight() => ProgressWeight;
  36. private bool InProgress { get; set; }
  37. public void ResetProgress() => InProgress = false;
  38. public string ErrorString() => $"SystemPackageAction failed to remove '{Name}'.";
  39. public UninstallTaskStatus GetStatus()
  40. {
  41. if (InProgress) return UninstallTaskStatus.InProgress;
  42. return HasFinished ? UninstallTaskStatus.Completed : UninstallTaskStatus.ToDo;
  43. }
  44. private bool HasFinished = false;
  45. public async Task<bool> RunTask()
  46. {
  47. if (InProgress) throw new TaskInProgressException("Another Appx action was called while one was in progress.");
  48. InProgress = true;
  49. Console.WriteLine($"Removing system package '{Name}'...");
  50. var excludeArgs = new StringBuilder("");
  51. if (RegexExcludeList != null)
  52. {
  53. foreach (var regex in RegexExcludeList)
  54. {
  55. excludeArgs.Append(@$" -xf ""{regex}""");
  56. }
  57. }
  58. var excludeDependsArgs = new StringBuilder("");
  59. if (ExcludeDependentsList != null)
  60. {
  61. foreach (var dependent in ExcludeDependentsList)
  62. {
  63. excludeDependsArgs.Append(@$" -xdependent ""{dependent}""");
  64. }
  65. }
  66. var psi = new ProcessStartInfo()
  67. {
  68. UseShellExecute = false,
  69. CreateNoWindow = true,
  70. Arguments = $@"-SystemPackage ""{Name}"" -Arch {Arch.ToString()} -Language ""{Language}""" + excludeArgs + excludeDependsArgs,
  71. FileName = Directory.GetCurrentDirectory() + "\\ame-assassin\\ame-assassin.exe",
  72. RedirectStandardOutput = true,
  73. RedirectStandardError = true
  74. };
  75. var proc = Process.Start(psi);
  76. proc.OutputDataReceived += ProcOutputHandler;
  77. proc.ErrorDataReceived += ProcOutputHandler;
  78. proc.BeginOutputReadLine();
  79. proc.BeginErrorReadLine();
  80. bool exited = proc.WaitForExit(30000);
  81. // WaitForExit alone seems to not be entirely reliable
  82. while (!exited && ExeRunning(proc))
  83. {
  84. exited = proc.WaitForExit(30000);
  85. }
  86. using (var log = new StreamWriter("Logs\\Packages.txt", true))
  87. log.Write(output.ToString());
  88. HasFinished = true;
  89. InProgress = false;
  90. return true;
  91. }
  92. private StringBuilder output = new StringBuilder("");
  93. private bool PleaseWait = false;
  94. private void ProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
  95. {
  96. var write = outLine == null ? "" : outLine.Data;
  97. output.Append(write + Environment.NewLine);
  98. if (String.IsNullOrEmpty(write)) return;
  99. if (write.StartsWith("--- Removing"))
  100. {
  101. Console.WriteLine(write.Substring(4, write.Length - 4));
  102. PleaseWait = true;
  103. }
  104. if (write.StartsWith("Waiting for the service to stop...") && PleaseWait)
  105. {
  106. PleaseWait = false;
  107. Console.WriteLine("This may take some time...");
  108. }
  109. }
  110. private static bool ExeRunning(Process process)
  111. {
  112. try
  113. {
  114. return Process.GetProcessesByName(process.ProcessName).Any(x => x.Id == process.Id);
  115. }
  116. catch (Exception)
  117. {
  118. return false;
  119. }
  120. }
  121. }
  122. }