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.

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