Skip to main content

Overview

BCU supports quiet (silent) and unattended uninstallation modes that minimize or eliminate user interaction during the uninstall process. This is essential for automation, scripting, and batch operations where manual intervention is impractical.

Quiet Uninstall Detection

BCU automatically detects if an application supports quiet uninstallation:
[LocalisedName(typeof(Localisation), nameof(Localisation.QuietUninstallPossible))]
public bool QuietUninstallPossible => 
    !string.IsNullOrEmpty(QuietUninstallString) ||
    (UninstallerKind == UninstallerType.Msiexec &&
     BundleProviderKey != Guid.Empty);

Explicit Support

Application has a QuietUninstallString in registry

MSI Packages

All Windows Installer packages support silent mode

Generated Parameters

BCU generates silent switches for known installer types

User-Defined

Custom quiet uninstall strings can be manually specified

Quiet Uninstall String Sources

Applications may specify a quiet uninstall command in the registry:
private static string GetQuietUninstallString(RegistryKey uninstallerKey)
{
    return uninstallerKey.GetStringSafe(RegistryNameQuietUninstallString);
}
Registry Location: HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\{AppKey}\QuietUninstallString

Running Quiet Uninstalls

Bulk Operations

When running bulk uninstalls, BCU automatically uses quiet mode when available:
public void RunUninstaller(RunUninstallerOptions options)
{
    var uninstallString = IsSilentPossible && UninstallerEntry.QuietUninstallPossible
        ? UninstallerEntry.QuietUninstallString
        : UninstallerEntry.UninstallString;

    using (var uninstaller = UninstallerEntry.RunUninstaller(
        options.PreferQuiet, options.Simulate, _canRetry))
    {
        if (options.PreferQuiet && UninstallerEntry.QuietUninstallPossible)
        {
            try
            {
                // Lower priority for background operation
                uninstaller.PriorityClass = ProcessPriorityClass.BelowNormal;
            }
            catch { }
        }
        
        // Wait for completion
        // ...
    }
}

Command Line

BCU can be automated via command line:
# Uninstall specific application quietly
BCUninstaller.exe /uninstall "Application Name" /quiet

# Batch uninstall from list
BCUninstaller.exe /uninstall-list "apps.bcul" /quiet /auto
Quiet mode bypasses user prompts. Ensure you’ve reviewed what will be uninstalled before using automated modes.

Automation Features

Quiet uninstallers can hang without user notification. BCU monitors for stuck processes:
private bool TestUninstallerForStalls(IEnumerable<string> childProcesses)
{
    // Create performance counters for CPU and I/O
    foreach (var childProcessName in childProcessNames)
    {
        var perfCounters = new[]
        {
            new PerformanceCounter("Process", "% Processor Time", childProcessName),
            new PerformanceCounter("Process", "IO Data Bytes/sec", childProcessName)
        };
        _perfCounterBuffer.Add(childProcessName, new PerfCounterEntry(perfCounters));
    }

    // Wait to gather data
    Thread.Sleep(1100);

    // Check if any process is active
    foreach (var perfCounterEntry in _perfCounterBuffer)
    {
        var cpuUsage = CalculateCpuUsage(perfCounterEntry);
        var ioUsage = CalculateIoUsage(perfCounterEntry);

        // Check if process seems to be doing anything
        // Use 1% for CPU and 10KB for I/O
        if (cpuUsage <= 1 && ioUsage <= 10240)
        {
            return true; // Process is stalled
        }
    }
    
    return false;
}
Stall Criteria:
  • CPU usage ≤ 1%
  • I/O activity ≤ 10KB/sec
  • Detected for 30+ consecutive checks
Auto-Kill: idleCounter > 30 triggers automatic termination
Failed quiet uninstalls can retry with interactive mode:
if (error != null)
{
    if (options.RetryFailedQuiet || 
        (UninstallerEntry.UninstallerKind == UninstallerType.Nsis && 
         !options.PreferQuiet))
    {
        retry = true;
        throw new IOException(
            Localisation.UninstallError_UninstallerReturnedCode + exitVar);
    }
}

if (retry && _canRetry)
{
    CurrentStatus = UninstallStatus.Waiting;
    _canRetry = false;  // Only retry once
}
else
{
    Finished = true;
}
Retry Behavior:
  • First attempt: Quiet mode
  • On failure: Retry with interactive mode
  • Only retries once per application
BCU interprets uninstaller exit codes:
var exitVar = uninstaller.ExitCode;
if (exitVar != 0)
{
    if (UninstallerEntry.UninstallerKind == UninstallerType.Msiexec &&
        exitVar == 1602)
    {
        // 1602 ERROR_INSTALL_USEREXIT - User cancelled
        _skipLevel = SkipCurrentLevel.Skip;
    }
    else if (UninstallerEntry.UninstallerKind == UninstallerType.Nsis &&
             (exitVar == 1 || exitVar == 2))
    {
        // 1 - Installation aborted by user
        // 2 - Installation aborted by script
        _skipLevel = SkipCurrentLevel.Skip;
    }
    else if (exitVar == -1073741510)
    {
        // 0xC000013A - Terminated by CTRL+C
        _skipLevel = SkipCurrentLevel.Terminate;
    }
    else
    {
        switch (exitVar)
        {
            case 2:
                throw new Exception("The system cannot find the file specified.");
            case 3:
                throw new Exception("The system cannot find the path specified.");
            case 5:
                throw new Exception("Access is denied.");
            case 9009:
                throw new Exception("Program is not recognized as an internal or external command.");
            default:
                if (options.RetryFailedQuiet)
                    retry = true;
                throw new IOException(
                    Localisation.UninstallError_UninstallerReturnedCode + exitVar);
        }
    }
}
BCU monitors the entire process tree:
var watchedProcesses = new List<Process> { uninstaller };
int[] previousWatchedProcessIds = { };

while (true)
{
    // Add all child processes
    foreach (var watchedProcess in watchedProcesses.ToList())
        watchedProcesses.AddRange(watchedProcess.GetChildProcesses());

    // For MSI, also track msiexec
    if (UninstallerEntry.UninstallerKind == UninstallerType.Msiexec)
    {
        foreach (var msiProcess in Process.GetProcessesByName("msiexec"))
            watchedProcesses.AddRange(msiProcess.GetChildProcesses());
    }

    watchedProcesses = CleanupDeadProcesses(watchedProcesses).ToList();

    // Check if we are done
    if (watchedProcesses.Count == 0)
        break;
        
    // Continue monitoring...
}

Quiet Uninstall Daemon

For enhanced automation, BCU includes a daemon that can assist with interactive installers:
Experimental Feature: The Quiet Uninstall Daemon attempts to automatically answer common uninstaller dialogs. This feature is experimental and may not work with all uninstallers.
if (IsSilentPossible && UninstallToolsGlobalConfig.UseQuietUninstallDaemon && _canRetry)
{
    // Don't try to automatize CLI programs or our own helpers
    if (!UninstallerEntry.QuietUninstallerIsCLI() && 
        !UninstallerEntry.QuietUninstallString.Contains(
            UninstallToolsGlobalConfig.AppLocation, 
            StringComparison.OrdinalIgnoreCase))
    {
        var processIds = SafeGetProcessIds(watchedProcesses).ToArray();
        options.Owner.SendProcessesToWatchToDeamon(
            processIds.Except(previousWatchedProcessIds));
    }
}

Configuration Options

Prefer Quiet

Use quiet mode when available during bulk operations

Auto-Kill Stuck

Automatically terminate uninstallers that appear stuck

Retry Failed

Retry failed quiet uninstalls in interactive mode

Concurrent Limit

Maximum number of simultaneous quiet uninstallers

Settings

private BulkUninstallConfiguration GetConfiguration(bool quiet)
{
    return new BulkUninstallConfiguration(
        _settings.AdvancedDisableProtection,
        quiet,  // Prefer quiet mode
        _settings.AdvancedSimulate,
        _settings.QuietAutoKillStuck,  // Auto-kill stuck uninstallers
        _settings.QuietRetryFailedOnce  // Retry failed once
    );
}

Process Priority Management

Quiet uninstallers run at lower priority to minimize system impact:
if (options.PreferQuiet && UninstallerEntry.QuietUninstallPossible)
{
    try
    {
        uninstaller.PriorityClass = ProcessPriorityClass.BelowNormal;
    }
    catch
    {
        // Don't care if setting this fails
    }
}
Resource Management: Background uninstallers are deprioritized so you can continue working while the batch operation completes.

Common Silent Switches

Different installer types use different silent switches:
# Silent uninstall
msiexec.exe /x {ProductGUID} /qn

# Silent with no restart
msiexec.exe /x {ProductGUID} /qn /norestart

# Passive (progress bar, no interaction)
msiexec.exe /x {ProductGUID} /qb
Parameters:
  • /x: Uninstall
  • /qn: No UI
  • /qb: Basic UI (progress only)
  • /norestart: Suppress restart prompts

Best Practices

Test First

Test quiet uninstalls on non-critical systems before automating

Enable Monitoring

Keep auto-kill and retry options enabled for reliable automation

Set Reasonable Limits

Don’t run too many concurrent uninstallers (3-5 is optimal)

Review Logs

Check logs after batch operations to catch failures
Administrator Rights: Many uninstallers require administrator privileges. Run BCU as administrator for full automation support.

Bulk Uninstall

Learn about bulk uninstallation operations

Application Detection

How BCU detects quiet uninstall capabilities

Build docs developers (and LLMs) love