Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Junk" removal switch to BCU-Console #581

Merged
merged 11 commits into from
May 10, 2024
2 changes: 1 addition & 1 deletion doc/BCU_manual.html

Large diffs are not rendered by default.

Binary file modified doc/BCU_manual.odt
Binary file not shown.
55 changes: 52 additions & 3 deletions source/BCU-console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Apache License Version 2.0
*/

using Klocman.Extensions;
using System;
using System.Collections.Generic;
using System.Globalization;
Expand All @@ -13,6 +14,9 @@ Apache License Version 2.0
using System.Threading;
using UninstallTools;
using UninstallTools.Factory;
using UninstallTools.Junk;
using UninstallTools.Junk.Confidence;
using UninstallTools.Junk.Containers;
using UninstallTools.Lists;
using UninstallTools.Uninstaller;

Expand All @@ -24,7 +28,7 @@ private static void ShowHelp()
{
Console.WriteLine(@"BCU-console [help | /?] - Show help (this screen)

BCU-console uninstall [drive:][path]filename [/Q] [/U] [/V] - Uninstall applications.
BCU-console uninstall [drive:][path]filename [/Q] [/U] [/V] [/J=<Level>] - Uninstall applications.
[drive:][path] – Specifies drive and directory of the uninstall list.
filename – Specifies filename of the .bcul uninstall list that contains information about
what applications to uninstall.
Expand All @@ -40,6 +44,10 @@ what applications to uninstall.
/U - Unattended mode (do not ask user for confirmation). WARNING: ONLY USE AFTER
THOROUGH TESTING. UNINSTALL LISTS SHOULD BE AS SPECIFIC AS POSSIBLE TO AVOID
FALSE POSITIVES. THERE ARE NO WARRANTIES, USE WITH CAUTION.
/J=<Level> - Attempt to clean up leftover ""junk"" (Registry entries and files/folders) after
uninstall. If no level is passed then defaults to ""VeryGood"". ***WARNING***: USE
EXTREME CAUTION WHEN CHOOSING ANY LEVEL BELOW VeryGood. THERE ARE NO WARRANTIES.
Valid levels are: VeryGood, Good, Questionable, Bad, Unknown
/V - Verbose logging mode (show more information about what is currently happening).

Return codes:
Expand Down Expand Up @@ -178,13 +186,28 @@ private static int ProcessUninstallCommand(string[] args)
var isQuiet = args.Any(x => x.Equals("/Q", StringComparison.OrdinalIgnoreCase));
var isUnattended = args.Any(x => x.Equals("/U", StringComparison.OrdinalIgnoreCase));

int junkArgumentIndex = Array.FindIndex(args, a => a.Equals("/J", StringComparison.OrdinalIgnoreCase));
string junkArg = args.Where(a => a.Equals("/J", StringComparison.OrdinalIgnoreCase) || a.StartsWith("/J=", StringComparison.OrdinalIgnoreCase)).FirstOrDefault() ?? string.Empty;
ConfidenceLevel? junkConfidenceLevel = null;
if(junkArg.IsNotEmpty()) {
string[] junkSplit = junkArg.Split('=', 2);
junkConfidenceLevel = ConfidenceLevel.VeryGood;
if (junkSplit.Length == 2) {
if (!Enum.TryParse(junkSplit[1], out ConfidenceLevel parsedJunkConfidenceLevel)) {
Console.WriteLine($"An invalid junk confidence level was passed: {junkSplit[1]}");
ShowHelp();
return 1;
}
junkConfidenceLevel = parsedJunkConfidenceLevel;
}
}
if (isUnattended)
Console.WriteLine(@"WARNING: Running in unattended mode. To abort press Ctrl+C or close the window.");

return RunUninstall(list, isQuiet, isUnattended, isVerbose);
return RunUninstall(list, isQuiet, isUnattended, isVerbose, junkConfidenceLevel);
}

private static int RunUninstall(UninstallList list, bool isQuiet, bool isUnattended, bool isVerbose)
private static int RunUninstall(UninstallList list, bool isQuiet, bool isUnattended, bool isVerbose, ConfidenceLevel? junkConfidenceLevel = null)
{
Console.WriteLine(@"Starting bulk uninstall...");
var apps = QueryApps(isQuiet, isUnattended, isVerbose);
Expand Down Expand Up @@ -243,6 +266,32 @@ private static int RunUninstall(UninstallList list, bool isQuiet, bool isUnatten
while (!isDone)
Thread.Sleep(250);

if (junkConfidenceLevel is not null) {
Console.WriteLine($"Starting junk cleanup with a minimum confidence level of {junkConfidenceLevel}");
List<IJunkResult> remainingJunk = JunkManager.FindJunk(apps, apps, _ => { })
.Where(j => j.Confidence.GetConfidence() >= junkConfidenceLevel)
.ToList();

if (!remainingJunk.Any()) {
Console.WriteLine($"No remaining junk found for any target applications.");
return 0;
}

Console.WriteLine("The following junk items will be permanently deleted:");
remainingJunk.ForEach(Console.WriteLine);
if (!isUnattended) {
Console.WriteLine(@"Do you want to continue? [Y]es/[N]o");
if (Console.ReadKey(true).Key != ConsoleKey.Y)
return CancelledByUser();
}

foreach (ApplicationUninstallerEntry entry in apps) {
// ApplicationUninstallerEntry doesn't currently implement an equality operator so ToLongString() will do as an object "hash".
List<IJunkResult> appJunk = remainingJunk.Where(j => j.Application.ToLongString().Equals(entry.ToLongString())).ToList();
Console.WriteLine($"{entry.DisplayName} Junk - {appJunk.Count} Entries Found");
appJunk.ForEach(j => j.Delete());
}
}
return 0;
}

Expand Down