github no-faff/InstallerClean v1.5.2

latest releases: v2.3.0, v2.3.0-preview, v2.2.0...
3 months ago

What's new

Safety

  • Move now refuses any destination inside C:\Windows\Installer at the service layer, not just at the UI. A bug in a future entry point that forgot to validate can no longer move files back into themselves.
  • Destinations that are junctions or symlinks pointing into C:\Windows\Installer are detected and blocked. Previously a carefully-placed junction could have let Move write files into the Installer folder itself.
  • Delete now uses the Shell SHFileOperationW API directly instead of VB's FileSystem.DeleteFile, removing a thread-apartment risk where error dialogs could deadlock.
  • The large-file warning on delete also fires when any single file is over 500 MB, not just when the total is over 1 GB. Windows can silently skip the Recycle Bin for individual large files too.

Cancellation

  • The initial startup scan can now be cancelled with a Cancel button on the splash screen, or by pressing Esc. Previously the app would lock you out until the scan finished.
  • Rescan can be cancelled too. The scanning overlay now shows a Cancel button, and Esc cancels a running scan.
  • Selecting a file in the Registered or Orphaned Files windows kicks off a background MSI metadata read. That read is now cancelled when you close the window, so there's no lingering work.

Window behaviour

  • Main window is resizable with a Maximise button in the title bar. Content stays centred and max-bounded so large monitors don't stretch the layout awkwardly.
  • Move destination field is editable. Type or paste a path, or use Browse. The value is persisted on focus loss.
  • Confirmation dialogs (Move, Delete) can now be dragged by their top edge.

Clarified UX

  • Completion screen: the secondary button is now "Scan again" and actually triggers a rescan instead of just dismissing the overlay. Primary stays as "Close" and defaults to Enter.
  • Column sort in the Registered Files window shows an arrow for the active column and direction, with the initial ProductName ascending state shown on open.
  • Large-size delete warning is clearer about why Windows may skip the Recycle Bin, and points users to Move if they want guaranteed backups.
  • Error messages when the Move destination is unusable now tell you why (no permission, path too long, folder missing, drive error) rather than showing a raw framework message.

Robustness

  • Move destination on a network share (UNC path like \\server\share) no longer crashes the free-space check. The check is skipped silently if the destination can't be measured.
  • Move destination is probed once before the copy loop starts. If the folder is read-only or unwritable you see a single clean error rather than per-file failures for every file in the batch.
  • Update check's HTTP response has a 256 KB cap so a compromised or misbehaving endpoint can't flood memory.
  • Installer product enumeration bails cleanly after 20 consecutive API errors instead of spinning. Hard 10,000-index cap keeps the loop finite.
  • Zero products from the Windows Installer API (indicates a corrupt installer database) now produces a targeted error pointing you at sfc /scannow, rather than a silent "all clear" scan.
  • About window: Check for updates is resilient to any unexpected exception from the update service.
  • Crash log rotates at 512 KB and timestamps use offset-aware format so cross-timezone sharing is unambiguous.
  • Settings save never throws: a disk-full or locked-file situation shows a friendly warning instead of crashing, and a stranded settings.json.tmp is cleaned up automatically.
  • Cancel during the last microsecond of an operation no longer throws ObjectDisposedException.
  • Scan failures now write to the crash log so you can share details for diagnosis.

Diagnostics

  • Registered but missing on disk: if the Windows Installer API tells us a package lives at a path that no longer exists on disk, the main window shows a warning with the count. Your install is genuinely broken in this state and you would want to know.
  • Richer file details: the Orphaned and Registered details panels now surface two extra fields from each file's Summary Information stream, Application (PID_APPNAME) and Keywords (PID_KEYWORDS), alongside Author, Title, Subject, Digital signature and Comment.
  • CLI Event Log entry: each /s, /d or /m CLI run now writes a single summary entry to the Windows Application event log under source "InstallerClean". Useful for Task Scheduler / unattended deployments where stdout is not captured.

CLI

  • installerclean-cli.exe is shipped in the installer so CLI usage (/s, /d, /m) waits properly when called from PowerShell or cmd. It's a small console launcher (about 44 KB, static, no runtime dependency) whose source is in cli-launcher/launcher.c.

Behind the scenes

  • Added global.json pinning the .NET SDK and Directory.Build.props turning on ContinuousIntegrationBuild for Release builds. Release binaries are deterministic across machines.
  • Dropped PublishReadyToRun from release builds for smaller binaries and determinism across runtime patch versions.
  • Version is defined once in Directory.Build.props; the release script reads it and passes it to Inno Setup via /DAppVersion=, so installer and assembly can't drift.
  • Extracted IDialogService abstraction so ViewModels don't depend on WPF's MessageBox directly.
  • UpdateCheckService is IDisposable and its HttpClient is released on app exit.
  • Migrated certificate handling to X509Certificate2 + X500DistinguishedName.Format(multiLine:true), which properly handles quoted commas in subjects like CN="Acme, Inc.", O=Acme. Removed the CommaToNewlineConverter.
  • Replaced FileSystem.DeleteFile (VB runtime) with direct SHFileOperationW P/Invoke to avoid STA apartment requirements on worker threads.
  • RegisteredPackage carries the file size now. The scan service fills it once; the Details window no longer stats the disk on the UI thread.
  • Registry-fallback packages (no ProductCode) group by their package path so each becomes its own row instead of collapsing into one "(unknown)" entry.
  • Spacing tokens (Space.*, Gap.*, GapBottom.*, GapRight.*) defined in App.xaml and applied across the windows.
  • Every hardcoded colour hex in the window XAMLs has been replaced with a reference to the existing brush resources, so changing the palette is now a single-file edit.
  • Progress<T> handlers are uniform (method groups); ProductRow / PatchRow live with the other records under Models/; Post-operation rescan no longer stacks overlays; RefreshAsync removed (duplicated ScanAsync).
  • Symmetric event-handler unsubscription in Orphaned, Registered and Main windows. Detail ViewModels are IDisposable and their lifetime token is cancelled on window close.
  • Accessibility: every interactive control has an AutomationProperties.Name. Distinct names on the two "Details" buttons. Keyboard-focus visual feedback on pill buttons. Close buttons respond to Alt+C.
  • Splash progress formula now reaches 100 (it used to asymptote to 90); scrollbar dead-space padding removed.
  • SHFileOperation, StorageHelpers, dialog-service flow, scan-cancel, DescribeWriteFailure, real-directory FileSystemScanService, PruneEmptySubdirectories cancellation, UpdateCheckService disposal, CrashLog rotation, settings save fault paths, destination persistence, ScanCommand access-denied flow all have unit tests.
  • CI now smoke-publishes both self-contained and framework-dependent exes on every push and runs dotnet list --vulnerable.
  • Removed the "antivirus heuristic" guidance from CONTRIBUTING.md. It was a precaution without evidence and doesn't belong in a contributor doc.

Downloads

File Size Description
InstallerClean-setup.exe ~72 MB Recommended - Inno Setup installer (includes installerclean-cli.exe)
InstallerClean-portable.exe ~76 MB Self-contained, no install needed
InstallerClean-slim.exe ~7.7 MB Needs .NET 8 Desktop Runtime

The setup installer and portable exe bundle the .NET 8 runtime so nothing else needs to be installed. The slim exe is for machines that already have .NET 8.

All downloads require administrator privileges and Windows 10 or 11.

Verify your download (SHA256)

aea453c7193e4bc8484dfd5fd13aec139f3e7f74ba996e4ab841a2e1a383e8d2  InstallerClean-setup.exe
92490e622fdc390e24f4ce624ac5e5ac61c3e2fb4bdc8d96576d6e75dacf58dc  InstallerClean-portable.exe
49d57188d329ea34ae7c00c145f7a63920dd9a2e27f9eb129b3e9218d5908888  InstallerClean-slim.exe

Quick check in PowerShell (returns True on match, False on mismatch):

(Get-FileHash -Algorithm SHA256 .\InstallerClean-setup.exe).Hash -eq 'aea453c7193e4bc8484dfd5fd13aec139f3e7f74ba996e4ab841a2e1a383e8d2'

Substitute the filename and hash if checking the portable or slim build. For a manual visual check, run Get-FileHash -Algorithm SHA256 .\InstallerClean-setup.exe and compare the Hash output to the list above.

Don't miss a new InstallerClean release

NewReleases is sending notifications on new releases.