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.

151 lines
5.2 KiB

using System;
using System.Linq;
using System.Threading.Tasks;
using TrustedUninstaller.Shared.Exceptions;
using TrustedUninstaller.Shared.Tasks;
using YamlDotNet.Serialization;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
namespace TrustedUninstaller.Shared.Actions
{
// Integrate ame-assassin later
internal class SystemPackageAction : TaskAction, ITaskAction
{
public void RunTaskOnMainThread() { throw new NotImplementedException(); }
public enum Architecture
{
amd64 = 0,
wow64 = 1,
msil = 2,
x86 = 3,
All = 4
}
[YamlMember(typeof(string), Alias = "name")]
public string Name { get; set; }
[YamlMember(typeof(string), Alias = "arch")]
public Architecture Arch { get; set; } = Architecture.All;
[YamlMember(typeof(string), Alias = "language")]
public string Language { get; set; } = "*";
[YamlMember(typeof(string), Alias = "regexExcludeFiles")]
public string[]? RegexExcludeList { get; set; }
[YamlMember(typeof(string), Alias = "excludeDependents")]
public string[]? ExcludeDependentsList { get; set; }
[YamlMember(typeof(string[]), Alias = "weight")]
public int ProgressWeight { get; set; } = 15;
public int GetProgressWeight() => ProgressWeight;
private bool InProgress { get; set; }
public void ResetProgress() => InProgress = false;
public string ErrorString() => $"SystemPackageAction failed to remove '{Name}'.";
public UninstallTaskStatus GetStatus()
{
if (InProgress) return UninstallTaskStatus.InProgress;
return HasFinished ? UninstallTaskStatus.Completed : UninstallTaskStatus.ToDo;
}
private bool HasFinished = false;
public async Task<bool> RunTask()
{
if (InProgress) throw new TaskInProgressException("Another Appx action was called while one was in progress.");
InProgress = true;
Console.WriteLine($"Removing system package '{Name}'...");
var excludeArgs = new StringBuilder("");
if (RegexExcludeList != null)
{
foreach (var regex in RegexExcludeList)
{
excludeArgs.Append(@$" -xf ""{regex}""");
}
}
var excludeDependsArgs = new StringBuilder("");
if (ExcludeDependentsList != null)
{
foreach (var dependent in ExcludeDependentsList)
{
excludeDependsArgs.Append(@$" -xdependent ""{dependent}""");
}
}
string kernelDriverArg = AmeliorationUtil.UseKernelDriver ? " -UseKernelDriver" : "";
var psi = new ProcessStartInfo()
{
UseShellExecute = false,
CreateNoWindow = true,
Arguments = $@"-SystemPackage ""{Name}"" -Arch {Arch.ToString()} -Language ""{Language}""" + excludeArgs + excludeDependsArgs + kernelDriverArg,
FileName = Directory.GetCurrentDirectory() + "\\ame-assassin\\ame-assassin.exe",
RedirectStandardOutput = true,
RedirectStandardError = true
};
var proc = Process.Start(psi);
proc.OutputDataReceived += ProcOutputHandler;
proc.ErrorDataReceived += ProcOutputHandler;
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
bool exited = proc.WaitForExit(30000);
// WaitForExit alone seems to not be entirely reliable
while (!exited && ExeRunning(proc))
{
exited = proc.WaitForExit(30000);
}
using (var log = new StreamWriter("Logs\\Packages.txt", true))
log.Write(output.ToString());
HasFinished = true;
InProgress = false;
return true;
}
private StringBuilder output = new StringBuilder("");
private bool PleaseWait = false;
private void ProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
var write = outLine == null ? "" : outLine.Data;
output.Append(write + Environment.NewLine);
if (String.IsNullOrEmpty(write)) return;
if (write.StartsWith("--- Removing"))
{
Console.WriteLine(write.Substring(4, write.Length - 4));
PleaseWait = true;
}
if (write.StartsWith("Waiting for the service to stop...") && PleaseWait)
{
PleaseWait = false;
Console.WriteLine("This may take some time...");
}
}
private static bool ExeRunning(Process process)
{
try
{
return Process.GetProcessesByName(process.ProcessName).Any(x => x.Id == process.Id);
}
catch (Exception)
{
return false;
}
}
}
}