├── Tests ├── TestScripts │ ├── Invalid │ │ ├── Empty.xml │ │ ├── Garbage.xml │ │ ├── Incomplete.xml │ │ ├── InvalidData1.xml │ │ └── InvalidData2.xml │ └── Valid │ │ ├── Hello World.xml │ │ ├── Wait 1 second.xml │ │ ├── Wait 2 seconds.xml │ │ ├── Wait 3 seconds.xml │ │ ├── Wait 4 seconds.xml │ │ ├── Wait 5 seconds.xml │ │ ├── Launch Notepad.xml │ │ ├── WhitespaceMadness.xml │ │ ├── Noise.xml │ │ └── CreateOrDeleteFile.xml └── ScriptXmlSerializerTests.cs ├── WinClean ├── WinClean.ico ├── Resources │ └── Images │ │ ├── Cross.ico │ │ ├── Gear.png │ │ ├── Pause.png │ │ ├── Play.png │ │ ├── Skipped.png │ │ ├── WinClean.png │ │ └── Checkmark.ico ├── Properties │ ├── InstallerScript.iss │ ├── launchSettings.json │ ├── AssemblyInfo.cs │ ├── PersistentSettings.settings │ ├── PublishProfiles │ │ ├── win-x64.pubxml │ │ ├── win-x86.pubxml │ │ ├── portable-win-x64.pubxml │ │ └── portable-win-x86.pubxml │ ├── PersistentSettings.Designer.cs │ ├── deploy.ps1 │ └── Settings.settings ├── Model │ ├── ExecutionResult.cs │ ├── Metadatas │ │ ├── ITextProvider.cs │ │ ├── Category.cs │ │ ├── Impact.cs │ │ ├── SafetyLevel.cs │ │ ├── LocalizedStringTextProvider.cs │ │ ├── ScriptType.cs │ │ ├── FSVerb.cs │ │ ├── ScriptExecutionState.cs │ │ ├── ResourceTextProvider.cs │ │ ├── ProgramHost.cs │ │ ├── ShellHost.cs │ │ ├── Usage.cs │ │ ├── Host.cs │ │ ├── OrderedMetadata.cs │ │ ├── Metadata.cs │ │ └── Capability.cs │ ├── Serialization │ │ ├── DeserializationException.cs │ │ ├── DeserializationChainException.cs │ │ ├── ScriptBuilder.cs │ │ ├── IScriptSerializer.cs │ │ └── IScriptMetadataDeserializer.cs │ ├── Scripts │ │ ├── ScriptAlreadyExistsException.cs │ │ ├── ScriptRepository.cs │ │ ├── EmbeddedScriptRepository.cs │ │ ├── Script.cs │ │ └── MutableScriptRepository.cs │ ├── HostStartInfo.cs │ ├── FileSystemException.cs │ ├── DisposableEnumerable.cs │ ├── ScriptAction.cs │ ├── AppDirectory.cs │ ├── HostTempFileStartInfo.cs │ ├── SourceControlClient.cs │ ├── ErrorCallbacks.cs │ ├── Multiton.cs │ ├── TempFile.cs │ ├── LocalizedString.cs │ ├── Cached.cs │ ├── DispatcherSynchronizeInvoke.cs │ └── TypedEnumerableDictionary.cs ├── View │ ├── Pages │ │ ├── Page1.xaml.cs │ │ ├── Page2.xaml.cs │ │ ├── Page3.xaml.cs │ │ ├── Page1.xaml │ │ └── Page3.xaml │ ├── Windows │ │ ├── MainWindow.xaml.cs │ │ ├── AboutWindow.xaml.cs │ │ ├── SettingsWindow.xaml.cs │ │ ├── ScriptExecutionWizard.xaml.cs │ │ └── AboutWindow.xaml │ ├── Controls │ │ ├── ExecutionInfoListView.xaml.cs │ │ ├── ExecutionInfoView.xaml.cs │ │ ├── ScriptActionDictionaryView.xaml.cs │ │ ├── ScriptSelectionView.xaml.cs │ │ ├── WizardPageBetter.cs │ │ ├── ScriptView.xaml.cs │ │ └── ScriptListView.xaml.cs │ ├── StandardIcons.cs │ ├── Converters │ │ ├── IsNotNullConverter.cs │ │ ├── BooleanInvertConverter.cs │ │ ├── ItemsEqualConverter.cs │ │ ├── EqualsOrDoNothingConverter.cs │ │ ├── GetMetadatasConverter.cs │ │ ├── IntEnumerableToStringConverter.cs │ │ ├── ColorToBrushConverter.cs │ │ ├── GoldenRatioConverter.cs │ │ ├── SemVersionRangeConverter.cs │ │ ├── DictionaryLookupConverter.cs │ │ └── CurrentVersionSatisfiesRangeConverter.cs │ ├── Validation │ │ └── SemVersionRangeValidationRule.cs │ ├── ResourceDictionaries │ │ └── Fixes.xaml │ ├── Behaviors │ │ ├── DataGridLastColumnFill.cs │ │ └── ConfirmWindowClosing.cs │ ├── App.ConsoleCallbacks.cs │ ├── ButtonsArea.cs │ └── App.xaml ├── ViewModel │ ├── Logging │ │ ├── LogLevel.cs │ │ ├── Logging.MockLogger.cs │ │ ├── Logging.cs │ │ ├── Logging.ConsoleLogger.cs │ │ ├── Logger.cs │ │ └── Logging.CsvLogger.cs │ ├── Pages │ │ ├── Page1ViewModel.cs │ │ ├── WizardPageViewModel.cs │ │ └── Page3ViewModel.cs │ ├── ExecutionResultViewModel.cs │ ├── Windows │ │ ├── AboutViewModel.cs │ │ ├── SettingsViewModel.cs │ │ └── ScriptExecutionWizardViewModel.cs │ ├── ScriptSelection.cs │ ├── ObservableSet.cs │ ├── CollectionWrapper.cs │ ├── ScriptActionViewModel.cs │ └── ExecutionProgressViewModel.cs ├── Services │ ├── IOperatingSystem.cs │ ├── IMetadatasProvider.cs │ ├── IDialogCreator.cs │ ├── FilterBuilder.cs │ ├── IMessageFormatter.cs │ ├── IThemeProvider.cs │ ├── IFilterBuilder.cs │ ├── ApplicationInfo.cs │ ├── ViewFactory.cs │ ├── OperatingSystem.cs │ ├── IApplicationInfo.cs │ ├── ServiceProvider.cs │ ├── IScriptStorage.cs │ ├── DialogCreator.cs │ ├── IViewFactory.cs │ ├── ExtensionGroup.cs │ ├── ISettings.cs │ ├── MetadatasProvider.cs │ ├── ThemeProvider.cs │ ├── MessageFormatter.cs │ └── ScriptStorage.cs ├── Scripts │ ├── Remove WordPad.xml │ ├── Remove PowerShell ISE.xml │ ├── Run the System File Checker tool.xml │ ├── Optimize drives.xml │ ├── Clear event logs.xml │ ├── Remove Internet Explorer 11.xml │ ├── Schedule Check Disk utility.xml │ ├── Remove the Microsoft Windows Malware Removal Tool.xml │ ├── Delete all system restore points, except the most recent.xml │ ├── Remove scheduled tasks.xml │ ├── Disable systematic short filename creation.xml │ ├── Show file extensions.xml │ ├── Clear File Explorer history.xml │ ├── Run Component Store cleanup.xml │ ├── Remove shortcut sufffix.xml │ ├── Run Service Pack cleanup.xml │ ├── Disable Timeline.xml │ ├── Show full path in Explorer title bar.xml │ ├── Show checkboxes near files and folders.xml │ ├── Disable Explorer online help.xml │ ├── Show seconds in taskbar clock.xml │ ├── Disable delivery optimization.xml │ ├── Repair system using Dism's cleanup image.xml │ ├── Disable Start menu web search.xml │ ├── Disable hibernation.xml │ ├── Disable Recent search history.xml │ ├── Stop apps from running in the background.xml │ ├── Don't block downloaded files.xml │ ├── Keep thumbnail cache after reboot.xml │ ├── Enable Verbose status messages.xml │ ├── Delete junk files.xml │ ├── Disable Cortana.xml │ ├── Remove Microsoft Edge.xml │ ├── Run advanced disk cleanup.xml │ └── Disable UAC prompt desktop dimming.xml ├── TypeEventHandler.cs ├── SafetyLevels.xml ├── Categories.xml ├── app.manifest ├── Hosts.xml └── Impacts.xml ├── CONTRIBUTING.md ├── LICENSE ├── .github └── ISSUE_TEMPLATE │ └── script-request.md ├── README.md ├── README.fr.md └── .gitattributes /Tests/TestScripts/Invalid/Empty.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /WinClean/WinClean.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5cover/WinClean/HEAD/WinClean/WinClean.ico -------------------------------------------------------------------------------- /Tests/ScriptXmlSerializerTests.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5cover/WinClean/HEAD/Tests/ScriptXmlSerializerTests.cs -------------------------------------------------------------------------------- /WinClean/Resources/Images/Cross.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5cover/WinClean/HEAD/WinClean/Resources/Images/Cross.ico -------------------------------------------------------------------------------- /WinClean/Resources/Images/Gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5cover/WinClean/HEAD/WinClean/Resources/Images/Gear.png -------------------------------------------------------------------------------- /WinClean/Resources/Images/Pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5cover/WinClean/HEAD/WinClean/Resources/Images/Pause.png -------------------------------------------------------------------------------- /WinClean/Resources/Images/Play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5cover/WinClean/HEAD/WinClean/Resources/Images/Play.png -------------------------------------------------------------------------------- /WinClean/Resources/Images/Skipped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5cover/WinClean/HEAD/WinClean/Resources/Images/Skipped.png -------------------------------------------------------------------------------- /WinClean/Resources/Images/WinClean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5cover/WinClean/HEAD/WinClean/Resources/Images/WinClean.png -------------------------------------------------------------------------------- /WinClean/Properties/InstallerScript.iss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5cover/WinClean/HEAD/WinClean/Properties/InstallerScript.iss -------------------------------------------------------------------------------- /WinClean/Resources/Images/Checkmark.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5cover/WinClean/HEAD/WinClean/Resources/Images/Checkmark.ico -------------------------------------------------------------------------------- /WinClean/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "WinClean": { 4 | "commandName": "Project" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /Tests/TestScripts/Invalid/Garbage.xml: -------------------------------------------------------------------------------- 1 | dfs;m*es%o,gjvlz d!:cxm¤,gl mbefd!v:r 2 | "tgerrgmùf*D 3 | mfc^ùgzrgm:g:ùf 4 | mf:lzùê*:f 5 | f;:lù*:sd§ 6 | elf*:DS -------------------------------------------------------------------------------- /WinClean/Model/ExecutionResult.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.Model; 2 | 3 | public sealed record ExecutionResult(int ExitCode, bool Succeeded, TimeSpan ExecutionTime); -------------------------------------------------------------------------------- /WinClean/View/Pages/Page1.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.View.Pages; 2 | 3 | public sealed partial class Page1 4 | { 5 | public Page1() => InitializeComponent(); 6 | } -------------------------------------------------------------------------------- /WinClean/View/Pages/Page2.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.View.Pages; 2 | 3 | public sealed partial class Page2 4 | { 5 | public Page2() => InitializeComponent(); 6 | } -------------------------------------------------------------------------------- /WinClean/View/Pages/Page3.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.View.Pages; 2 | 3 | public sealed partial class Page3 4 | { 5 | public Page3() => InitializeComponent(); 6 | } -------------------------------------------------------------------------------- /WinClean/View/Windows/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.View.Windows; 2 | 3 | public sealed partial class MainWindow 4 | { 5 | public MainWindow() => InitializeComponent(); 6 | } -------------------------------------------------------------------------------- /WinClean/View/Windows/AboutWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.View.Windows; 2 | 3 | public sealed partial class AboutWindow 4 | { 5 | public AboutWindow() => InitializeComponent(); 6 | } -------------------------------------------------------------------------------- /WinClean/View/Windows/SettingsWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.View.Windows; 2 | 3 | public sealed partial class SettingsWindow 4 | { 5 | public SettingsWindow() => InitializeComponent(); 6 | } -------------------------------------------------------------------------------- /WinClean/View/Controls/ExecutionInfoListView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.View.Controls; 2 | 3 | public sealed partial class ExecutionInfoListView 4 | { 5 | public ExecutionInfoListView() => InitializeComponent(); 6 | } -------------------------------------------------------------------------------- /WinClean/View/Windows/ScriptExecutionWizard.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.View.Windows; 2 | 3 | public sealed partial class ScriptExecutionWizard 4 | { 5 | public ScriptExecutionWizard() => InitializeComponent(); 6 | } -------------------------------------------------------------------------------- /WinClean/ViewModel/Logging/LogLevel.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.ViewModel.Logging; 2 | 3 | public enum LogLevel 4 | { 5 | Verbose = 0, 6 | Info = 1, 7 | Warning = 2, 8 | Error = 3, 9 | Critical = 4, 10 | } -------------------------------------------------------------------------------- /WinClean/Model/Metadatas/ITextProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace Scover.WinClean.Model.Metadatas; 4 | 5 | public interface ITextProvider 6 | { 7 | string GetDescription(CultureInfo culture); 8 | 9 | string GetName(CultureInfo culture); 10 | } -------------------------------------------------------------------------------- /WinClean/Services/IOperatingSystem.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.Services; 2 | 3 | /// Interacts with the operating system. 4 | public interface IOperatingSystem 5 | { 6 | public void OpenSystemPropertiesProtection(); 7 | 8 | public void RestartForOSReconfig(bool force); 9 | } -------------------------------------------------------------------------------- /WinClean/Model/Metadatas/Category.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.Model.Metadatas; 2 | 3 | public sealed class Category : OrderedMetadata 4 | { 5 | public Category(LocalizedString name, LocalizedString description, int order) : base(new LocalizedStringTextProvider(name, description), order) 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /WinClean/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | [assembly: System.Windows.ThemeInfo(System.Windows.ResourceDictionaryLocation.None, System.Windows.ResourceDictionaryLocation.SourceAssembly)] 4 | [assembly: ComVisible(false)] 5 | [assembly: Guid("ec827a36-8882-4b4f-a423-8c1983e28de3")] -------------------------------------------------------------------------------- /WinClean/Model/Metadatas/Impact.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.Model.Metadatas; 2 | 3 | /// Effect of running a script. 4 | public sealed class Impact : Metadata 5 | { 6 | public Impact(LocalizedString name, LocalizedString description) : base(new LocalizedStringTextProvider(name, description)) 7 | { 8 | } 9 | } -------------------------------------------------------------------------------- /Tests/TestScripts/Valid/Hello World.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tests/TestScripts/Invalid/Incomplete.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WinClean/ViewModel/Logging/Logging.MockLogger.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.ViewModel.Logging; 2 | 3 | public static partial class Logging 4 | { 5 | private sealed class MockLogger : Logger 6 | { 7 | public override Task ClearLogsAsync() => Task.CompletedTask; 8 | 9 | protected override void Log(LogEntry entry) 10 | { 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /WinClean/Services/IMetadatasProvider.cs: -------------------------------------------------------------------------------- 1 | using Scover.WinClean.Model; 2 | using Scover.WinClean.Model.Metadatas; 3 | 4 | namespace Scover.WinClean.Services; 5 | 6 | public interface IMetadatasProvider 7 | { 8 | StringComparison Comparison { get; } 9 | TypedEnumerableDictionary Metadatas { get; } 10 | 11 | T GetMetadata(string invariantName) where T : Metadata; 12 | } -------------------------------------------------------------------------------- /Tests/TestScripts/Invalid/InvalidData1.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tests/TestScripts/Invalid/InvalidData2.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tests/TestScripts/Valid/Wait 1 second.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tests/TestScripts/Valid/Wait 2 seconds.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tests/TestScripts/Valid/Wait 3 seconds.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tests/TestScripts/Valid/Wait 4 seconds.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tests/TestScripts/Valid/Wait 5 seconds.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tests/TestScripts/Valid/Launch Notepad.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WinClean/Services/IDialogCreator.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.Services; 2 | 3 | /// Creates modal dialog windows from a view model. 4 | public interface IDialogCreator 5 | { 6 | public bool? ShowDialog(TViewModel viewModel); 7 | 8 | public IReadOnlyList ShowOpenFileDialog(string filter = "", string defaultExtension = "", bool multiselect = false, bool readonlyChecked = false); 9 | } -------------------------------------------------------------------------------- /WinClean/Model/Serialization/DeserializationException.cs: -------------------------------------------------------------------------------- 1 | using Scover.WinClean.Resources; 2 | 3 | namespace Scover.WinClean.Model.Serialization; 4 | 5 | public class DeserializationException : Exception 6 | { 7 | public DeserializationException(string targetName, Exception? innerException = null) 8 | : base(ExceptionMessages.DeserializationFailed.FormatWith(targetName), innerException) 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /WinClean/View/Controls/ExecutionInfoView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Scover.WinClean.ViewModel; 2 | 3 | namespace Scover.WinClean.View.Controls; 4 | 5 | public sealed partial class ExecutionInfoView 6 | { 7 | public ExecutionInfoView() => InitializeComponent(); 8 | 9 | private void TextEditor_Scroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e) => ((ExecutionInfoViewModel)Content).NotifyScroll.Execute(e); 10 | } -------------------------------------------------------------------------------- /WinClean/View/StandardIcons.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Media; 2 | 3 | using static Vanara.PInvoke.Shell32; 4 | 5 | namespace Scover.WinClean.View; 6 | 7 | public static class StandardIcons 8 | { 9 | public static ImageSource Error { get; } = SHSTOCKICONID.SIID_ERROR.ToBitmapSource(SHGSI.SHGSI_SMALLICON); 10 | public static ImageSource Warning { get; } = SHSTOCKICONID.SIID_WARNING.ToBitmapSource(SHGSI.SHGSI_SMALLICON); 11 | } -------------------------------------------------------------------------------- /WinClean/ViewModel/Pages/Page1ViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.Input; 2 | 3 | using Scover.WinClean.Services; 4 | 5 | namespace Scover.WinClean.ViewModel.Pages; 6 | 7 | public sealed class Page1ViewModel : WizardPageViewModel 8 | { 9 | public static IRelayCommand OpenSystemProtectionSettings { get; } = new RelayCommand(() 10 | => ServiceProvider.Get().OpenSystemPropertiesProtection()); 11 | } -------------------------------------------------------------------------------- /WinClean/Model/Scripts/ScriptAlreadyExistsException.cs: -------------------------------------------------------------------------------- 1 | using Scover.WinClean.Resources; 2 | 3 | namespace Scover.WinClean.Model.Scripts; 4 | 5 | public sealed class ScriptAlreadyExistsException : Exception 6 | { 7 | public ScriptAlreadyExistsException(Script existingScript, Exception? innerException = null) 8 | : base(ExceptionMessages.ScriptAlreadyExists.FormatWith(existingScript.InvariantName), innerException) 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /WinClean/Properties/PersistentSettings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /WinClean/Services/FilterBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.Services; 2 | 3 | public sealed class FilterBuilder : IFilterBuilder 4 | { 5 | public string Combine(IEnumerable filters) => string.Join('|', filters); 6 | 7 | public string Make(string name, IEnumerable extensions) 8 | { 9 | string extensionsPart = string.Join(";", extensions.Select(ext => $"*{ext}")); 10 | return $"{name} ({extensionsPart})|{extensionsPart}"; 11 | } 12 | } -------------------------------------------------------------------------------- /WinClean/Model/HostStartInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.Model; 2 | 3 | /// Information for executing a script host program. 4 | public class HostStartInfo : IDisposable 5 | { 6 | public HostStartInfo(string filename, string arguments) 7 | => (Filename, Arguments) = (filename, arguments); 8 | 9 | public virtual string Arguments { get; } 10 | public string Filename { get; } 11 | 12 | public virtual void Dispose() => GC.SuppressFinalize(this); 13 | } -------------------------------------------------------------------------------- /WinClean/Model/Metadatas/SafetyLevel.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Media; 2 | 3 | namespace Scover.WinClean.Model.Metadatas; 4 | 5 | public sealed class SafetyLevel : OrderedMetadata 6 | { 7 | /// The color of the safety level. 8 | public SafetyLevel(LocalizedString name, LocalizedString description, int order, Color color) : base(new LocalizedStringTextProvider(name, description), order) 9 | => Color = color; 10 | 11 | public Color Color { get; } 12 | } -------------------------------------------------------------------------------- /WinClean/Services/IMessageFormatter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace Scover.WinClean.Services; 4 | 5 | /// 6 | /// ICU Message formatter. 7 | /// 8 | /// Supports the humanize Time and Date format. 9 | public interface IMessageFormatter 10 | { 11 | string Format(string message, IReadOnlyDictionary args); 12 | 13 | string Format(string message, CultureInfo culture, IReadOnlyDictionary args); 14 | } -------------------------------------------------------------------------------- /WinClean/View/Converters/IsNotNullConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Data; 3 | 4 | namespace Scover.WinClean.View.Converters; 5 | 6 | public sealed class IsNotNullConverter : IValueConverter 7 | { 8 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => value is not null; 9 | 10 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => throw new NotSupportedException(); 11 | } -------------------------------------------------------------------------------- /WinClean/Services/IThemeProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Media; 3 | 4 | namespace Scover.WinClean.Services; 5 | 6 | /// Provides themed styles for UI components. 7 | public interface IThemeProvider 8 | { 9 | TextStyle MainInstruction { get; } 10 | 11 | Brush PausedProgressBarBrush { get; } 12 | } 13 | 14 | public sealed record TextStyle( 15 | Brush Foreground, 16 | double FontSize, 17 | FontFamily FontFamily, 18 | FontWeight FontWeight); -------------------------------------------------------------------------------- /WinClean/View/Converters/BooleanInvertConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Data; 3 | 4 | namespace Scover.WinClean.View.Converters; 5 | 6 | public sealed class BooleanInvertConverter : IValueConverter 7 | { 8 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => !(bool)value.NotNull(); 9 | 10 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => !(bool)value.NotNull(); 11 | } -------------------------------------------------------------------------------- /WinClean/View/Converters/ItemsEqualConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Data; 3 | 4 | namespace Scover.WinClean.View.Converters; 5 | 6 | public sealed class ItemsEqualConverter : IMultiValueConverter 7 | { 8 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) => values.Distinct().Count() == 1; 9 | 10 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotSupportedException(); 11 | } -------------------------------------------------------------------------------- /Tests/TestScripts/Valid/WhitespaceMadness.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 29 | -------------------------------------------------------------------------------- /WinClean/Services/IFilterBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.Services; 2 | 3 | public interface IFilterBuilder 4 | { 5 | string Combine(params string[] filters) => Combine((IEnumerable)filters); 6 | 7 | string Combine(IEnumerable filters); 8 | 9 | string Make(ExtensionGroup extensionGroup) => Make(extensionGroup.Name, extensionGroup); 10 | 11 | string Make(string name, IEnumerable extensions); 12 | 13 | string Make(string name, params string[] extensions) => Make(name, (IEnumerable)extensions); 14 | } -------------------------------------------------------------------------------- /WinClean/Model/Metadatas/LocalizedStringTextProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace Scover.WinClean.Model.Metadatas; 4 | 5 | public sealed class LocalizedStringTextProvider : ITextProvider 6 | { 7 | private readonly LocalizedString _description, _name; 8 | 9 | public LocalizedStringTextProvider(LocalizedString name, LocalizedString description) => (_name, _description) = (name, description); 10 | 11 | public string GetDescription(CultureInfo culture) => _description[culture]; 12 | 13 | public string GetName(CultureInfo culture) => _name[culture]; 14 | } -------------------------------------------------------------------------------- /WinClean/Model/FileSystemException.cs: -------------------------------------------------------------------------------- 1 | using Scover.WinClean.Model.Metadatas; 2 | using Scover.WinClean.Resources; 3 | 4 | namespace Scover.WinClean.Model; 5 | 6 | /// An exception thrown by the filesystem. 7 | public sealed class FileSystemException : Exception 8 | { 9 | public FileSystemException(Exception innerException, FSVerb verb, string element, string? message = null) : base(message ?? ExceptionMessages.FileSystemException, innerException) 10 | => (Element, Verb) = (element, verb); 11 | 12 | public string Element { get; } 13 | public FSVerb Verb { get; } 14 | } -------------------------------------------------------------------------------- /WinClean/View/Converters/EqualsOrDoNothingConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | using System.Windows.Data; 4 | 5 | namespace Scover.WinClean.View.Converters; 6 | 7 | public sealed class EqualsOrDoNothingConverter : IValueConverter 8 | { 9 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 10 | => Equals(value, parameter); 11 | 12 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) 13 | => (bool)value.NotNull() 14 | ? parameter 15 | : Binding.DoNothing; 16 | } -------------------------------------------------------------------------------- /WinClean/ViewModel/ExecutionResultViewModel.cs: -------------------------------------------------------------------------------- 1 | using ExecutionResult = Scover.WinClean.Model.ExecutionResult; 2 | 3 | namespace Scover.WinClean.ViewModel; 4 | 5 | public sealed class ExecutionResultViewModel 6 | { 7 | private readonly ExecutionResult _model; 8 | 9 | public ExecutionResultViewModel(ExecutionResult model) => _model = model; 10 | 11 | public TimeSpan ExecutionTime => _model.ExecutionTime; 12 | public int ExitCode => _model.ExitCode; 13 | public string FormattedExecutionTime => ExecutionTime.HumanizeToMilliseconds(); 14 | public bool Succeeded => _model.Succeeded; 15 | } -------------------------------------------------------------------------------- /WinClean/Model/Metadatas/ScriptType.cs: -------------------------------------------------------------------------------- 1 | using Scover.WinClean.Resources; 2 | 3 | namespace Scover.WinClean.Model.Metadatas; 4 | 5 | public sealed class ScriptType : OrderedMetadata 6 | { 7 | private ScriptType(string resourceName, int order, bool isMutable) : base(new ResourceTextProvider(ScriptTypes.ResourceManager, resourceName), order) 8 | => IsMutable = isMutable; 9 | 10 | public static ScriptType Custom { get; } = new(nameof(ScriptTypes.Custom), 1, true); 11 | public static ScriptType Default { get; } = new(nameof(ScriptTypes.Default), 0, false); 12 | public bool IsMutable { get; } 13 | } -------------------------------------------------------------------------------- /WinClean/View/Converters/GetMetadatasConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Data; 3 | 4 | using Scover.WinClean.Services; 5 | 6 | namespace Scover.WinClean.View.Converters; 7 | 8 | public sealed class GetMetadatasConverter : IValueConverter 9 | { 10 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 11 | => ServiceProvider.Get().Metadatas[(Type)value.NotNull()]; 12 | 13 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => throw new NotSupportedException(); 14 | } -------------------------------------------------------------------------------- /WinClean/ViewModel/Windows/AboutViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | using CommunityToolkit.Mvvm.Input; 3 | 4 | using Scover.WinClean.Services; 5 | 6 | namespace Scover.WinClean.ViewModel.Windows; 7 | 8 | public sealed class AboutViewModel : ObservableObject 9 | { 10 | public static string ApplicationName => ServiceProvider.Get().Name; 11 | public static string ApplicationVersion => ServiceProvider.Get().Version; 12 | public static IRelayCommand OpenRepository => new RelayCommand(ServiceProvider.Get().RepositoryUrl.Open); 13 | } -------------------------------------------------------------------------------- /Tests/TestScripts/Valid/Noise.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WinClean/View/Converters/IntEnumerableToStringConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Data; 3 | 4 | namespace Scover.WinClean.View.Converters; 5 | 6 | public sealed class IntEnumerableToStringConverter : IValueConverter 7 | { 8 | private const char SeparatorChar = ' '; 9 | 10 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => string.Join(SeparatorChar, (IEnumerable)value.NotNull()); 11 | 12 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => throw new NotSupportedException(); 13 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Scripts 4 | 5 | Don't hesitate to submit new scripts to embed into WinClean by creating an issue with the provided template. 6 | 7 | ## Localization roadmap 8 | 9 | - [x] Localize RESX resource files. 10 | - [x] Create issues for globalization problems (i.e. text doesn't fit). 11 | - [x] Create a pull request for the translation. 12 | - [x] Localize the ``Messages`` and ``CustomMessages`` section in ``InstallerScript.iss``. 13 | 14 | - [ ] Localize RESX resources marked as ``@Invariant`` in the comment. 15 | - [ ] Localize string literals. 16 | - [ ] Localize HREFs in links. 17 | 18 | -------------------------------------------------------------------------------- /WinClean/View/Controls/ScriptActionDictionaryView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace Scover.WinClean.View.Controls; 4 | 5 | public sealed partial class ScriptActionDictionaryView 6 | { 7 | public static readonly DependencyProperty IsReadOnlyProperty 8 | = DependencyProperty.Register(nameof(IsReadOnly), typeof(bool), typeof(ScriptActionDictionaryView)); 9 | 10 | public ScriptActionDictionaryView() => InitializeComponent(); 11 | 12 | public bool IsReadOnly 13 | { 14 | get => (bool)GetValue(IsReadOnlyProperty); 15 | set => SetValue(IsReadOnlyProperty, value); 16 | } 17 | } -------------------------------------------------------------------------------- /WinClean/View/Converters/ColorToBrushConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Data; 3 | using System.Windows.Media; 4 | 5 | namespace Scover.WinClean.View.Converters; 6 | 7 | public sealed class ColorToBrushConverter : IValueConverter 8 | { 9 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => new SolidColorBrush((Color)value.NotNull()) { Opacity = System.Convert.ToDouble(parameter, culture) }; 10 | 11 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => ((SolidColorBrush)value.NotNull()).Color; 12 | } -------------------------------------------------------------------------------- /WinClean/View/Converters/GoldenRatioConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Data; 3 | 4 | using static System.Convert; 5 | 6 | namespace Scover.WinClean.View.Converters; 7 | 8 | public sealed class GoldenRatioConverter : IValueConverter 9 | { 10 | private static double GoldenRatio => (1 + Math.Sqrt(5)) / 2; 11 | 12 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => ToDouble(value, culture) * GoldenRatio; 13 | 14 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => ToDouble(value, culture) / GoldenRatio; 15 | } -------------------------------------------------------------------------------- /WinClean/Model/DisposableEnumerable.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace Scover.WinClean.Model; 4 | 5 | public sealed class DisposableEnumerable : IEnumerable, IDisposable where T : IDisposable 6 | { 7 | private readonly IEnumerable _items; 8 | 9 | public DisposableEnumerable(IEnumerable items) => _items = items; 10 | 11 | public void Dispose() 12 | { 13 | foreach (var item in _items) 14 | { 15 | item.Dispose(); 16 | } 17 | } 18 | 19 | public IEnumerator GetEnumerator() => _items.GetEnumerator(); 20 | 21 | IEnumerator IEnumerable.GetEnumerator() => _items.GetEnumerator(); 22 | } -------------------------------------------------------------------------------- /WinClean/Services/ApplicationInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Scover.WinClean.Services; 4 | 5 | public sealed class ApplicationInfo : IApplicationInfo 6 | { 7 | public Assembly Assembly { get; } = Assembly.GetExecutingAssembly(); 8 | public string Name => Assembly.GetCustomAttribute().NotNull().Product; 9 | public string RepositoryUrl => (Assembly.GetCustomAttributes().SingleOrDefault(metadata => metadata.Key == "RepositoryUrl")?.Value).NotNull(); 10 | public string Version => Assembly.GetCustomAttribute().NotNull().InformationalVersion; 11 | } -------------------------------------------------------------------------------- /WinClean/Properties/PublishProfiles/win-x64.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | FileSystem 10 | <_TargetId>Folder 11 | net6.0-windows7.0 12 | false 13 | win-x64 14 | false 15 | false 16 | 17 | -------------------------------------------------------------------------------- /WinClean/Properties/PublishProfiles/win-x86.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | FileSystem 10 | <_TargetId>Folder 11 | net6.0-windows7.0 12 | win-x86 13 | false 14 | false 15 | false 16 | 17 | -------------------------------------------------------------------------------- /WinClean/Properties/PublishProfiles/portable-win-x64.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | FileSystem 10 | <_TargetId>Folder 11 | net6.0-windows7.0 12 | win-x64 13 | false 14 | false 15 | true 16 | 17 | -------------------------------------------------------------------------------- /WinClean/Properties/PublishProfiles/portable-win-x86.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | FileSystem 10 | <_TargetId>Folder 11 | net6.0-windows7.0 12 | win-x86 13 | false 14 | false 15 | true 16 | 17 | -------------------------------------------------------------------------------- /WinClean/Model/Serialization/DeserializationChainException.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.Model.Serialization; 2 | 3 | public sealed class DeserializationChainException : DeserializationException 4 | { 5 | public DeserializationChainException(string targetName, IReadOnlyDictionary deserializerExceptions) 6 | : base(targetName) 7 | => DeserializerExceptions = deserializerExceptions; 8 | 9 | public IReadOnlyDictionary DeserializerExceptions { get; } 10 | 11 | public override string ToString() => string.Concat(DeserializerExceptions.Select(kv => $"{kv.Key}: {kv.Value.Message}{Environment.NewLine}")) + base.ToString(); 12 | } -------------------------------------------------------------------------------- /WinClean/Services/ViewFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace Scover.WinClean.Services; 4 | 5 | public sealed class ViewFactory : IViewFactory 6 | { 7 | private readonly Dictionary _viewsByViewModels = new(); 8 | 9 | public FrameworkElement MakeView(TViewModel viewModel) 10 | { 11 | var view = (FrameworkElement)Activator.CreateInstance(_viewsByViewModels[typeof(TViewModel)]).NotNull(); 12 | view.DataContext = viewModel; 13 | return view; 14 | } 15 | 16 | public void Register() where TView : FrameworkElement, new() 17 | => _viewsByViewModels.Add(typeof(TViewModel), typeof(TView)); 18 | } -------------------------------------------------------------------------------- /WinClean/View/Validation/SemVersionRangeValidationRule.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Controls; 3 | 4 | using Semver; 5 | 6 | namespace Scover.WinClean.View.Validation; 7 | 8 | public sealed class SemVersionRangeValidationRule : ValidationRule 9 | { 10 | public int MaxLength { get; set; } = 2048; 11 | public SemVersionRangeOptions Options { get; set; } 12 | 13 | public override ValidationResult Validate(object? value, CultureInfo cultureInfo) 14 | => SemVersionRange.TryParse((string)value.NotNull(), Options, out _, MaxLength) 15 | ? ValidationResult.ValidResult 16 | : new(false, Resources.UI.ScriptView.InvalidVersionRange); 17 | } -------------------------------------------------------------------------------- /WinClean/View/Controls/ScriptSelectionView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | using Scover.WinClean.Model.Metadatas; 4 | 5 | namespace Scover.WinClean.View.Controls; 6 | 7 | public sealed partial class ScriptSelectionView 8 | { 9 | public static readonly DependencyProperty UsageProperty = DependencyProperty.Register(nameof(Usage), typeof(Usage), typeof(ScriptSelectionView)); 10 | 11 | public ScriptSelectionView() => InitializeComponent(); 12 | 13 | public Usage Usage 14 | { 15 | get => (Usage)GetValue(UsageProperty); 16 | set => SetValue(UsageProperty, value); 17 | } 18 | } 19 | 20 | public sealed class SelectionDataTemplateDictionary : Dictionary { } -------------------------------------------------------------------------------- /WinClean/View/Converters/SemVersionRangeConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Data; 3 | 4 | using Semver; 5 | 6 | namespace Scover.WinClean.View.Converters; 7 | 8 | public sealed class SemVersionRangeConverter : IValueConverter 9 | { 10 | public int MaxLength { get; set; } = 2048; 11 | public SemVersionRangeOptions Options { get; set; } 12 | 13 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => ((SemVersionRange)value.NotNull()).ToString(); 14 | 15 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => SemVersionRange.Parse((string)value.NotNull(), Options, MaxLength); 16 | } -------------------------------------------------------------------------------- /WinClean/Scripts/Remove WordPad.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tests/TestScripts/Valid/CreateOrDeleteFile.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WinClean/Model/Metadatas/FSVerb.cs: -------------------------------------------------------------------------------- 1 | using Scover.WinClean.Resources; 2 | 3 | namespace Scover.WinClean.Model.Metadatas; 4 | 5 | public sealed class FSVerb : Metadata 6 | { 7 | private FSVerb(string resourceName) : base(new ResourceTextProvider(FSVerbs.ResourceManager, resourceName)) 8 | { 9 | } 10 | 11 | /// Access of a file system element. 12 | public static FSVerb Access { get; } = new(nameof(FSVerbs.Acess)); 13 | 14 | /// Creation of a file system element. 15 | public static FSVerb Create { get; } = new(nameof(FSVerbs.Create)); 16 | 17 | /// Deletion of a file system element. 18 | public static FSVerb Delete { get; } = new(nameof(FSVerbs.Delete)); 19 | } -------------------------------------------------------------------------------- /WinClean/View/ResourceDictionaries/Fixes.xaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | -------------------------------------------------------------------------------- /WinClean/Model/Metadatas/ScriptExecutionState.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.Model.Metadatas; 2 | 3 | public sealed class ScriptExecutionState : Metadata 4 | { 5 | private ScriptExecutionState(string resourceName) : base(new ResourceTextProvider(Resources.ScriptExecutionStates.ResourceManager, resourceName)) 6 | { 7 | } 8 | 9 | public static ScriptExecutionState Finished { get; } = new(nameof(Finished)); 10 | public static ScriptExecutionState Paused { get; } = new(nameof(Paused)); 11 | public static ScriptExecutionState Pending { get; } = new(nameof(Pending)); 12 | public static ScriptExecutionState Running { get; } = new(nameof(Running)); 13 | public static ScriptExecutionState Skipped { get; } = new(nameof(Skipped)); 14 | } -------------------------------------------------------------------------------- /WinClean/Model/Metadatas/ResourceTextProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Resources; 3 | 4 | namespace Scover.WinClean.Model.Metadatas; 5 | 6 | public sealed class ResourceTextProvider : ITextProvider 7 | { 8 | private readonly ResourceManager _resourceManager; 9 | 10 | public ResourceTextProvider(ResourceManager resourceManager, string resourceName) => (_resourceManager, ResourceName) = (resourceManager, resourceName); 11 | 12 | public string ResourceName { get; } 13 | 14 | public string GetDescription(CultureInfo culture) => _resourceManager.GetString(ResourceName + "Description", culture).NotNull(); 15 | 16 | public string GetName(CultureInfo culture) => _resourceManager.GetString(ResourceName, culture).NotNull(); 17 | } -------------------------------------------------------------------------------- /WinClean/Scripts/Remove PowerShell ISE.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WinClean/View/Converters/DictionaryLookupConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Diagnostics; 3 | using System.Globalization; 4 | using System.Windows.Data; 5 | 6 | namespace Scover.WinClean.View.Converters; 7 | 8 | public sealed class DictionaryLookupConverter : IMultiValueConverter 9 | { 10 | public object? Convert(object?[] values, Type targetType, object parameter, CultureInfo culture) 11 | { 12 | Debug.Assert(values.Length == 2); 13 | var dic = values[0] as IDictionary; 14 | var key = values[1]; 15 | return key is null ? null : dic?[key]; 16 | } 17 | 18 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotSupportedException(); 19 | } -------------------------------------------------------------------------------- /WinClean/ViewModel/ScriptSelection.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | using Scover.WinClean.Model.Metadatas; 4 | 5 | namespace Scover.WinClean.ViewModel; 6 | 7 | public sealed class ScriptSelection : ObservableObject 8 | { 9 | private Capability? _desiredCapability; 10 | private bool _isSelected; 11 | 12 | public Capability? DesiredCapability 13 | { 14 | get => _desiredCapability; 15 | set 16 | { 17 | _desiredCapability = value; 18 | OnPropertyChanged(); 19 | } 20 | } 21 | 22 | public bool IsSelected 23 | { 24 | get => _isSelected; 25 | set 26 | { 27 | _isSelected = value; 28 | OnPropertyChanged(); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /WinClean/Model/Metadatas/ProgramHost.cs: -------------------------------------------------------------------------------- 1 | using Semver; 2 | 3 | namespace Scover.WinClean.Model.Metadatas; 4 | 5 | public sealed class ProgramHost : Host 6 | { 7 | private readonly string _arguments, _executable, _extension; 8 | 9 | public ProgramHost(LocalizedString name, LocalizedString description, SemVersionRange versions, (string filename, int index)? icon, string executable, string arguments, string extension) : base(name, description, versions, icon) 10 | => (_executable, _arguments, _extension) = (Environment.ExpandEnvironmentVariables(executable), Environment.ExpandEnvironmentVariables(arguments), extension); 11 | 12 | public override HostStartInfo CreateHostStartInfo(string code) => new HostTempFileStartInfo(_executable, _arguments, code, _extension); 13 | } -------------------------------------------------------------------------------- /WinClean/View/Converters/CurrentVersionSatisfiesRangeConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | using System.Windows.Data; 4 | 5 | using Semver; 6 | 7 | namespace Scover.WinClean.View.Converters; 8 | 9 | public sealed class CurrentVersionSatisfiesRangeConverter : IValueConverter 10 | { 11 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 12 | { 13 | bool satisfies = SemVersion.FromVersion(Environment.OSVersion.Version.WithoutRevision()).Satisfies((SemVersionRange)value.NotNull()); 14 | return parameter is bool expected ? satisfies == expected : satisfies; 15 | } 16 | 17 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => throw new NotSupportedException(); 18 | } -------------------------------------------------------------------------------- /WinClean/Scripts/Run the System File Checker tool.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WinClean/ViewModel/ObservableSet.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | 3 | namespace Scover.WinClean.ViewModel; 4 | 5 | public sealed class ObservableSet : ObservableCollection 6 | { 7 | public ObservableSet(IEnumerable collection) : base(collection) 8 | { 9 | } 10 | 11 | protected override void InsertItem(int index, T item) 12 | { 13 | if (!Contains(item)) 14 | { 15 | base.InsertItem(index, item); 16 | } 17 | } 18 | 19 | protected override void SetItem(int index, T item) 20 | { 21 | int i = IndexOf(item); 22 | // If the item isn't already present or if we're replacing the same item, then we don't have a duplicate 23 | if (i < 0 || i == index) 24 | { 25 | base.SetItem(index, item); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /WinClean/Model/ScriptAction.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | using Scover.WinClean.Model.Metadatas; 4 | 5 | namespace Scover.WinClean.Model; 6 | 7 | [DebuggerDisplay($"{{{nameof(Host)},nq}} program")] 8 | public sealed class ScriptAction 9 | { 10 | public ScriptAction(Host host, ISet successExitCodes, string code, int order) 11 | => (Code, SuccessExitCodes, Host, Order) = (code, successExitCodes, host, order); 12 | 13 | public string Code { get; set; } 14 | public Host Host { get; set; } 15 | 16 | /// 17 | /// Gets or sets the order of execution. Actions with a lower order should be executed first. 18 | /// 19 | public int Order { get; set; } 20 | 21 | public ISet SuccessExitCodes { get; } 22 | 23 | public HostStartInfo CreateHostStartInfo() => Host.CreateHostStartInfo(Code); 24 | } -------------------------------------------------------------------------------- /WinClean/Scripts/Optimize drives.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WinClean/Scripts/Clear event logs.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WinClean/Scripts/Remove Internet Explorer 11.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WinClean/Model/AppDirectory.cs: -------------------------------------------------------------------------------- 1 | using Scover.WinClean.Services; 2 | 3 | using static System.Environment; 4 | 5 | namespace Scover.WinClean.Model; 6 | 7 | /// Represents a directory containing files related to the application. 8 | public static class AppDirectory 9 | { 10 | /// Gets the full path to the application's logging directory. 11 | public static string Logs { get; } = Create(Path.GetTempPath(), ServiceProvider.Get().Name, nameof(Logs)); 12 | 13 | /// Gets the full path to the application's scripts directory. 14 | public static string Scripts { get; } = Create(GetFolderPath(SpecialFolder.ApplicationData, SpecialFolderOption.DoNotVerify), ServiceProvider.Get().Name, nameof(Scripts)); 15 | 16 | private static string Create(params string[] paths) => Directory.CreateDirectory(Path.Join(paths)).FullName; 17 | } -------------------------------------------------------------------------------- /WinClean/Model/HostTempFileStartInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Scover.WinClean.Model; 2 | 3 | /// Information for executing a script host program that requires a temporary file. 4 | public sealed class HostTempFileStartInfo : HostStartInfo 5 | { 6 | private readonly string _incompleteArguments; 7 | private readonly Lazy _tempFile; 8 | 9 | public HostTempFileStartInfo(string filename, string incompleteArguments, string tempFileContents, string tempFileExtension) : base(filename, "") 10 | { 11 | _incompleteArguments = incompleteArguments; 12 | _tempFile = new(() => TempFile.Create("Script_{0}", tempFileExtension, tempFileContents)); 13 | } 14 | 15 | public override string Arguments => _incompleteArguments.FormatWith(_tempFile.Value.Filename); 16 | 17 | public override void Dispose() 18 | { 19 | _tempFile.DisposeIfCreated(); 20 | base.Dispose(); 21 | } 22 | } -------------------------------------------------------------------------------- /WinClean/ViewModel/Windows/SettingsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | using CommunityToolkit.Mvvm.ComponentModel; 4 | using CommunityToolkit.Mvvm.Input; 5 | 6 | using Scover.WinClean.Resources; 7 | using Scover.WinClean.Services; 8 | using Scover.WinClean.ViewModel.Logging; 9 | 10 | namespace Scover.WinClean.ViewModel.Windows; 11 | 12 | public sealed class SettingsViewModel : ObservableObject 13 | { 14 | public SettingsViewModel() => Reset = new RelayCommand(() => 15 | { 16 | Settings.Reset(); 17 | StaticPropertyChanged?.Invoke(this, new(nameof(Settings))); 18 | Logs.SettingsReset.Log(); 19 | }); 20 | 21 | // This event is subscribed to automatically by the WPF framework 22 | public static event PropertyChangedEventHandler? StaticPropertyChanged; 23 | 24 | public static ISettings Settings => ServiceProvider.Get(); 25 | public IRelayCommand Reset { get; } 26 | } -------------------------------------------------------------------------------- /WinClean/Scripts/Schedule Check Disk utility.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WinClean/Services/OperatingSystem.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | using Vanara.PInvoke; 4 | 5 | using static Vanara.PInvoke.AdvApi32; 6 | using static Vanara.PInvoke.SystemShutDownReason; 7 | 8 | namespace Scover.WinClean.Services; 9 | 10 | public sealed class OperatingSystem : IOperatingSystem 11 | { 12 | public void OpenSystemPropertiesProtection() 13 | => Process.Start(new ProcessStartInfo 14 | { 15 | FileName = Environment.ExpandEnvironmentVariables("%SYSTEMROOT%\\System32\\SystemPropertiesProtection.exe"), 16 | UseShellExecute = true, // This will show an UAC prompt if administrative privileges are required instead of throwing an exception 17 | }); 18 | 19 | public void RestartForOSReconfig(bool force) 20 | => Win32Error.ThrowLastErrorIfFalse(InitiateSystemShutdownEx(null, null, 0, force, true, 21 | SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG)); 22 | } -------------------------------------------------------------------------------- /WinClean/Scripts/Remove the Microsoft Windows Malware Removal Tool.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WinClean/Model/Metadatas/ShellHost.cs: -------------------------------------------------------------------------------- 1 | using Scover.WinClean.Resources; 2 | 3 | using Semver; 4 | 5 | using Vanara.PInvoke; 6 | 7 | namespace Scover.WinClean.Model.Metadatas; 8 | 9 | public sealed class ShellHost : Host 10 | { 11 | private readonly string _commandLine; 12 | 13 | public ShellHost(LocalizedString name, LocalizedString description, SemVersionRange versions, (string filename, int index)? icon, string commandLine) : base(name, description, versions, icon) => _commandLine = commandLine; 14 | 15 | public override HostStartInfo CreateHostStartInfo(string code) 16 | { 17 | string commandLine = _commandLine.FormatWith(code); 18 | var args = Win32Error.ThrowLastErrorIf(Shell32.CommandLineToArgvW(Environment.ExpandEnvironmentVariables(commandLine)), args => !args.Any(), ExceptionMessages.InvalidScriptCommandLine.FormatWith(commandLine)); 19 | return new(args[0], args.Length > 1 ? string.Join(' ', args[1..]) : ""); 20 | } 21 | } -------------------------------------------------------------------------------- /WinClean/View/Behaviors/DataGridLastColumnFill.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | using Microsoft.Xaml.Behaviors; 5 | 6 | namespace Scover.WinClean.View.Behaviors; 7 | 8 | public sealed class DataGridLastColumnFill : Behavior 9 | { 10 | protected override void OnAttached() 11 | { 12 | AssociatedObject.Loaded += ResizeColumns; 13 | AssociatedObject.SizeChanged += ResizeColumns; 14 | base.OnAttached(); 15 | } 16 | 17 | protected override void OnDetaching() 18 | { 19 | AssociatedObject.Loaded -= ResizeColumns; 20 | AssociatedObject.SizeChanged -= ResizeColumns; 21 | base.OnDetaching(); 22 | } 23 | 24 | private void ResizeColumns(object sender, RoutedEventArgs e) 25 | { 26 | if (AssociatedObject.Columns.LastOrDefault() is { } lastColumn) 27 | { 28 | lastColumn.Width = new(1, DataGridLengthUnitType.Star); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /WinClean/ViewModel/Windows/ScriptExecutionWizardViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | using Scover.WinClean.Services; 4 | using Scover.WinClean.ViewModel.Pages; 5 | 6 | namespace Scover.WinClean.ViewModel.Windows; 7 | 8 | public sealed class ScriptExecutionWizardViewModel : ObservableObject 9 | { 10 | public ScriptExecutionWizardViewModel(IReadOnlyList executionInfos) 11 | { 12 | CollectionWrapper, ExecutionInfoViewModel> executionInfosWrapper = new(executionInfos); 13 | Page2ViewModel = new(executionInfosWrapper); 14 | Page3ViewModel = new(executionInfosWrapper); 15 | } 16 | 17 | public static TextStyle MainInstruction => ServiceProvider.Get().MainInstruction; 18 | public Page1ViewModel Page1ViewModel { get; } = new(); 19 | public Page2ViewModel Page2ViewModel { get; } 20 | public Page3ViewModel Page3ViewModel { get; } 21 | } -------------------------------------------------------------------------------- /WinClean/Services/IApplicationInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Scover.WinClean.Services; 4 | 5 | /// Retrieves application information and metadata (such as assembly attributes). 6 | public interface IApplicationInfo 7 | { 8 | public Assembly Assembly { get; } 9 | 10 | /// Gets product name information. 11 | /// . 12 | public string Name { get; } 13 | 14 | /// Gets the RepositoryUrl assembly metadata. 15 | /// 16 | /// for = 17 | /// RepositoryUrl. 18 | /// 19 | public string RepositoryUrl { get; } 20 | 21 | /// Gets version information. 22 | /// . 23 | public string Version { get; } 24 | } -------------------------------------------------------------------------------- /WinClean/Model/Metadatas/Usage.cs: -------------------------------------------------------------------------------- 1 | using Scover.WinClean.Model.Scripts; 2 | 3 | namespace Scover.WinClean.Model.Metadatas; 4 | 5 | /// What a script can be used as. 6 | public sealed class Usage : OrderedMetadata 7 | { 8 | private readonly IReadOnlyCollection _capabilities; 9 | 10 | private Usage(string resourceName, int order, params Capability[] capabilities) : base(new ResourceTextProvider(Resources.Usages.ResourceManager, resourceName), order) 11 | => _capabilities = capabilities; 12 | 13 | public static Usage Actions { get; } = new(nameof(Actions), 0, Capability.Execute); 14 | public static IReadOnlyCollection Instances => Multiton.Instances; 15 | public static Usage Settings { get; } = new(nameof(Settings), 1, Capability.Enable, Capability.Disable); 16 | 17 | public static IEnumerable GetUsages(Script script) 18 | => Instances.Where(usage => usage._capabilities.All(script.Actions.Keys.Contains)); 19 | } -------------------------------------------------------------------------------- /WinClean/Services/ServiceProvider.cs: -------------------------------------------------------------------------------- 1 | using Jab; 2 | 3 | namespace Scover.WinClean.Services; 4 | 5 | [ServiceProvider] 6 | [Singleton(typeof(IDialogCreator), typeof(DialogCreator))] 7 | [Singleton(typeof(IApplicationInfo), typeof(ApplicationInfo))] 8 | [Singleton(typeof(IViewFactory), typeof(ViewFactory))] 9 | [Singleton(typeof(IOperatingSystem), typeof(OperatingSystem))] 10 | [Singleton(typeof(ISettings), typeof(Settings))] 11 | [Singleton(typeof(IThemeProvider), typeof(ThemeProvider))] 12 | [Singleton(typeof(IMetadatasProvider), typeof(MetadatasProvider))] 13 | [Singleton(typeof(IScriptStorage), typeof(ScriptStorage))] 14 | [Singleton(typeof(IFilterBuilder), typeof(FilterBuilder))] 15 | [Singleton(typeof(IMessageFormatter), typeof(MessageFormatter))] 16 | public sealed partial class ServiceProvider 17 | { 18 | private static readonly ServiceProvider instance = new(); 19 | 20 | private ServiceProvider() 21 | { 22 | } 23 | 24 | public static T Get() => instance.GetService(); 25 | } -------------------------------------------------------------------------------- /WinClean/Services/IScriptStorage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | 3 | using Scover.WinClean.Model; 4 | using Scover.WinClean.Model.Metadatas; 5 | using Scover.WinClean.Model.Scripts; 6 | 7 | namespace Scover.WinClean.Services; 8 | 9 | public interface IScriptStorage 10 | { 11 | ObservableCollection -------------------------------------------------------------------------------- /WinClean/ViewModel/Logging/Logging.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Scover.WinClean.ViewModel.Logging; 4 | 5 | public enum LoggingType 6 | { 7 | Console, 8 | Csv, 9 | } 10 | 11 | public static partial class Logging 12 | { 13 | public static Logger Logger { get; private set; } = new MockLogger(); 14 | 15 | public static void InitializeLogger(LoggingType desiredLoggingType) => Logger = desiredLoggingType switch 16 | { 17 | LoggingType.Console => new ConsoleLogger(), 18 | LoggingType.Csv => new CsvLogger(), 19 | _ => throw desiredLoggingType.NewInvalidEnumArgumentException(nameof(desiredLoggingType)), 20 | }; 21 | 22 | /// 23 | public static void Log(this string message, 24 | LogLevel lvl = LogLevel.Verbose, 25 | [CallerMemberName] string caller = "", 26 | [CallerLineNumber] int callLine = 0, 27 | [CallerFilePath] string callFile = "") 28 | => Logger.Log(message, lvl, caller, callLine, callFile); 29 | } -------------------------------------------------------------------------------- /WinClean/ViewModel/Pages/WizardPageViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | using CommunityToolkit.Mvvm.Input; 3 | 4 | namespace Scover.WinClean.ViewModel.Pages; 5 | 6 | public partial class WizardPageViewModel : ObservableObject 7 | { 8 | [ObservableProperty] 9 | private bool _canSelectNextPage; 10 | 11 | [ObservableProperty] 12 | private IRelayCommand? _enterCommand; 13 | 14 | [ObservableProperty] 15 | private IRelayCommand? _leaveCommand; 16 | 17 | /// 18 | /// Indicates that a page has requested cancelation of the wizard. 19 | /// 20 | public event TypeEventHandler? ClosingRequested; 21 | /// 22 | /// Indicates that a page has finished and that the wizard should navigate to the next page. 23 | /// 24 | public event TypeEventHandler? Finished; 25 | 26 | protected void OnClosingRequested() => ClosingRequested?.Invoke(this, EventArgs.Empty); 27 | 28 | protected void OnFinished() => Finished?.Invoke(this, EventArgs.Empty); 29 | } -------------------------------------------------------------------------------- /WinClean/Scripts/Remove scheduled tasks.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WinClean/View/Pages/Page1.xaml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 68 | 69 | -------------------------------------------------------------------------------- /WinClean/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | .xml 7 | 8 | 9 | NaN 10 | 11 | 12 | NaN 13 | 14 | 15 | NaN 16 | 17 | 18 | NaN 19 | 20 | 21 | False 22 | 23 | 24 | True 25 | 26 | 27 | False 28 | 29 | 30 | 00:01:00 31 | 32 | 33 | *-* 34 | 35 | 36 | *-* 37 | 38 | 39 | https://github.com/5cover/WinClean/releases/latest 40 | 41 | 42 | https://github.com/5cover/WinClean/wiki/ 43 | 44 | 45 | https://github.com/5cover/WinClean/issues/new 46 | 47 | 48 | 511304031 49 | 50 | 51 | False 52 | 53 | 54 | -------------------------------------------------------------------------------- /WinClean/Impacts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Ergonomics 5 | Ergonomie 6 | Improves system practicality, comfort and ease of use. 7 | Améliore la fonctionnalité du système, son confort et sa facilité d'utilisation. 8 | 9 | 10 | Free storage space 11 | Espace de stockage libre 12 | Frees up disk space. 13 | Libère de l'espace disque. 14 | 15 | 16 | Memory usage 17 | Utilisation mémoire 18 | Reduces idle system memory usage. 19 | Limite l'utilisation mémoire du système inactif. 20 | 21 | 22 | Network usage 23 | Utilisation réseau 24 | Reduces idle system network usage. 25 | Limite l'utilisation réseau du système inactif. 26 | 27 | 28 | Privacy 29 | Confidentialité 30 | Reduces the amout of diagnostic data and analytics sent to Microsoft. 31 | Réduit la quantitié de données de diagnostic et analyses envoyées à Microsoft. 32 | 33 | 34 | Shutdown time 35 | Temps d'arrêt 36 | Makes the shutdown process faster. 37 | Rend le processus d'arrêt plus rapide. 38 | 39 | 40 | Stability 41 | Stabilité 42 | Reduces the tendency of the system to crash, hang, or bluescreen. 43 | Réduit la tendance du système à planter, à se bloquer ou à afficher un écran bleu. 44 | 45 | 46 | Startup time 47 | Temps de démarrage 48 | Makes the startup process faster. 49 | Rend le processus de démarrage plus rapide. 50 | 51 | 52 | Storage speed 53 | Vitesse disque 54 | Improves the speed at which disk I/O operations are performed. 55 | Améliore la vitesse à laquelle les opérations d'E/S de disque sont exécutées. 56 | 57 | -------------------------------------------------------------------------------- /WinClean/ViewModel/Logging/Logging.CsvLogger.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Globalization; 3 | using System.Text; 4 | 5 | using CsvHelper; 6 | using CsvHelper.Configuration; 7 | 8 | using Scover.WinClean.Model; 9 | using Scover.WinClean.Resources; 10 | 11 | namespace Scover.WinClean.ViewModel.Logging; 12 | 13 | public static partial class Logging 14 | { 15 | private sealed class CsvLogger : Logger, IDisposable 16 | { 17 | private const string DateTimeFilenameFormat = "yyyy-MM-dd--HH-mm-ss"; 18 | private const string LogFileExtension = ".csv"; 19 | 20 | private readonly Lazy _csvWriter; 21 | 22 | private readonly string _currentLogFile; 23 | 24 | public CsvLogger() 25 | { 26 | _currentLogFile = Path.Join(AppDirectory.Logs, Process.GetCurrentProcess().StartTime.ToString(DateTimeFilenameFormat, DateTimeFormatInfo.InvariantInfo) + LogFileExtension); 27 | // Defer writer creation. This prevents creating of empty log file at the start of the program. 28 | _csvWriter = new(() => 29 | { 30 | CsvWriter writer = new(new StreamWriter(_currentLogFile, false, Encoding.Unicode), new CsvConfiguration(CultureInfo.InvariantCulture)); 31 | writer.WriteHeader(); 32 | return writer; 33 | }); 34 | } 35 | 36 | public override Task ClearLogsAsync() => Task.Run(() => 37 | { 38 | foreach (string logFile in Directory.EnumerateFiles(AppDirectory.Logs, $"*{LogFileExtension}").Where(CanLogFileBeDeleted)) 39 | { 40 | try 41 | { 42 | File.Delete(logFile); 43 | } 44 | catch (Exception e) when (e.IsFileSystemExogenous()) 45 | { 46 | Log(Logs.FailedToDeleteLogFile.FormatWith(logFile, e), LogLevel.Error); 47 | // Swallow the exception. Failing to delete a log file is not serious enough to justify 48 | // terminating the application with an unhandled exception. 49 | } 50 | } 51 | Log(Logs.ClearedLogsFolder); 52 | }); 53 | 54 | public void Dispose() => _csvWriter.Value.Dispose(); 55 | 56 | protected override void Log(LogEntry entry) 57 | { 58 | lock (_csvWriter) 59 | { 60 | _csvWriter.Value.NextRecord(); 61 | _csvWriter.Value.WriteRecord(entry); 62 | _csvWriter.Value.Flush(); 63 | } 64 | } 65 | 66 | private bool CanLogFileBeDeleted(string logFile) 67 | => DateTime.TryParseExact(Path.GetFileNameWithoutExtension(logFile), DateTimeFilenameFormat, 68 | DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None, out _) && logFile != _currentLogFile; 69 | } 70 | } --------------------------------------------------------------------------------