Skip to main content

Auto-Updater: How It Works

Applies to: MSI only. MSIX uses Microsoft Store / App Installer flows instead – see MSIX Features.

The auto-updater turns your installer into a self-updating product. Once installed, a Windows service ships alongside your app, polls a versioning endpoint you control, and silently installs new MSI builds when they appear – without prompting the user and without requesting elevation from the user.

For configuration, setup, and all property references see the companion page: Auto-updater configuration.


Why auto-update matters

Automatically updating software sounds like standard functionality, but the overwhelming majority of Windows applications lack it. From analysing over 10,000 applications and their update flows, we identified three root causes:

1. Lack of knowledge

Building a secure auto-updater requires deep understanding of the Windows OS, the MSI technology, code-signing trust chains, and the needs of both home users and enterprise IT. Most vendors think only about one audience:

  • Home users need a seamless, zero-friction experience.
  • IT professionals need the ability to disable or control updates across thousands of endpoints via tools like Microsoft Intune or Configuration Manager.

A great auto-updater serves both. Google Chrome is a prime example – its update mechanism is so reliable that many enterprises leave it enabled even for business-critical browsing.

2. Complicated systems

Even with knowledge, building such a system internally is a significant engineering effort. It must:

  • Cover all security scenarios (hijacked feeds, revoked certificates, interrupted downloads).
  • Integrate into the installer lifecycle.
  • Handle running processes gracefully.
  • Work for both per-machine and limited-user scenarios.

For most development teams, this is too time-consuming. The common alternative is simply telling users: "Go to our website and download the newer version."

3. Expensive solutions

Learning, building, and maintaining an update system takes time – and time is money. Paid off-the-shelf solutions exist, but from our research they often suffer from one or all of the same problems, translating into an expensive proposition.

How Master Packager Dev solves this

We used over a decade of experience observing how others build their applications and created auto-update functionality for our own products first. Once we solved our own problems, we made the solution available to everyone.

It takes only 18 lines of JSON to add auto-update to your application – using only basic information every developer already knows (service name, a URL, and a few regex patterns). The updater is built on a Windows service that can update a per-machine MSI even for limited users, similarly to how Google Chrome updates work. You need admin rights only during the first installation, and then users never think about updates again.

Read the full announcement: Add These 17 Lines and Your App Will Auto-Update


What it does

When msi.updater is set on a package, MPDEV adds a small Windows service to the MSI and registers it during install. Once running, the service:

  1. Updater behaves differently based on the configuration:
    • If scheduling is enabled (and notifications are not used), it runs silent background checks and upgrades on the schedule. It will wait for scheduling.initialDelay after start of service.
    • If notifications.triggers is configured, it waits for one of the listed trigger processes to launch before running the update check and display a notification to the user.
  2. Performs a GET request to latestVersionDescriptor.url over HTTPS.
  3. Parses the response with the regex matchers, extracting version, installerUrl, sha256, and (optionally) a "what's new" URL.
  4. Compares the parsed version against the currently installed version.
  5. If the version is newer:
    • If the update was triggered by the scheduler, it downloads the installer to a temp folder and verifies the SHA256 silently.
    • If the update was triggered by a listed trigger process, it shows a notification to the user; after confirmation, it downloads the installer to a temp folder and verifies the SHA256.
  6. Verifies that the digital signature of the new installer matches the signature of the currently installed one. If they differ, the upgrade is aborted.
  7. Installs the MSI.
  8. Sleeps for scheduling.interval and loops back. Failures (busy installer, app running) sleep for scheduling.retryInterval instead.

Because the service runs as LocalSystem, the user does not need to be an administrator to receive updates. This is the main reason teams ship the auto-updater instead of relying on users to re-run the installer manually.


If the user dismisses the notification, no install is started from that notification event. The service waits for the next trigger event.


Internal architecture

Under the hood the auto-updater consists of three cooperating components, all shipped inside the same MSI:

ComponentRuns asRole
Scheduler (Windows service)LocalSystemLong-running service. Manages timers, watches for trigger processes, and spawns the updater process when needed.
Updater processLocalSystem (child of Scheduler)Short-lived process that executes a single update transaction: download, validate, install. Uses the same executable as the scheduler, started with different command-line switches.
Updater UICurrent userLightweight front-end shown via notification triggers. Displays download/install progress and relays user decisions back to the updater process. Has no control over file downloads, integrity checks, or where files are placed.

The scheduler and updater process communicate internally. The Updater UI communicates with the scheduler (and by extension the updater process) over named pipes, giving it a two-way channel to receive progress messages and send back limited user decisions.

Key design principle: The UI running in the user's session is intentionally unprivileged. All security decisions (trust validation, signature matching, integrity checks) happen exclusively in the LocalSystem processes. A compromised user account cannot influence the update pipeline.


Service startup and trust validation

Every time the scheduler service starts (first install, reboot, or manual restart), it performs a self-trust check before doing anything:

Service start


┌────────────────────────────────┐
│ Is the updater executable │
│ signed with a trusted cert? │
└───────────────┬────────────────┘

┌───────┴───────┐
│ yes │ no
▼ ▼
Continue Service stops
(configure immediately.
timers & Will not start
triggers) until re-signed.

What this means in practice:

  • Unsigned updater → MSI installation fails entirely (the installer refuses to register a service that isn't signed).
  • Signed with an untrusted certificate → MSI installation fails.
  • Certificate revoked after install → the service will not start on the next reboot. It silently prevents itself from running, protecting endpoints from executing code whose trust chain has been broken.

This self-check ensures that even if a certificate is revoked mid-day while the service is already running, the next reboot will block it. The running service does not poll its own certificate continuously (to avoid wasting CPU cycles), but it delegates trust re-verification to the updater process it spawns. Additionally, if the updater process ever reports an ExecutableIntegrityCheckFailed result, the scheduler service stops itself immediately — preventing any further update attempts until the issue is resolved.


Silent update flow (detailed)

When the scheduler's timer fires, the following happens step by step:

1. Version check

The scheduler fetches latestVersionDescriptor.url, applies the regex matchers, and compares the parsed version to the installed ProductVersion. If the versions match (or the installed version is higher), it logs "application is up to date" and sleeps until the next interval.

2. Spawn the updater process

If a newer version is found, the scheduler launches the updater process (same executable, different switches). This process also runs as LocalSystem.

3. Self-trust re-validation

The updater process immediately validates that it itself is still signed and trusted. If the certificate was revoked since the service started, the process stops and no update occurs. This closes the window between scheduler start and the actual update attempt.

4. Double-check version availability

Even though the scheduler already confirmed a new version, the updater process re-fetches the feed and re-parses it. This is needed both to confirm the update is still available and to obtain the download URL.

5. Download the installer

The updater downloads the MSI from installerUrl to a protected folder under %ProgramData%. If the file was already downloaded by a previous (retried) attempt and still exists on disk, the download is skipped.

6. Integrity validation

Three checks are performed on the downloaded file:

  1. SHA256 checksum – the hash of the file on disk must match the value from the feed. This confirms the download was not corrupted or interrupted.
  2. Digital signature validity – the MSI must carry a valid, trusted digital signature.
  3. Signature match – the signer of the downloaded MSI must match the certificate that signed the updater executable itself. The match is determined by comparing certificate thumbprints. For Azure Trusted Signing certificates (where thumbprints rotate with each signing operation), the updater falls back to comparing Enhanced Key Usage (EKU) OIDs — if both certificates carry matching Trusted Signing EKU identifiers (OID prefix 1.3.6.1.4.1.311.97.*), they are considered equivalent. If a different (even valid) certificate signed the file, the update is rejected.

If any check fails, the downloaded file is deleted immediately and the scheduler re-arms the timer for the next normal interval. On the next cycle the updater will attempt a fresh download.

7. Pre-installation checks

  • Another MSI installation in progress? The updater checks whether another MSI installation is already running (Windows Installer mutex). If yes, it reports failure and the scheduler retries after retryInterval (default 3 minutes).
  • Application files in use? If the MSI install would need to replace files currently locked by a running app, the silent install fails. The scheduler retries after retryInterval.

8. Installation

The updater installs the MSI using the native Windows Installer API (MsiInstallProduct) directly — it does not shell out to msiexec.exe. The install runs fully silent with verbose logging enabled. Current updater configuration values (scheduling intervals, notification settings, log retention) are forwarded as MSI properties so the new version inherits the same settings.

On success, the downloaded MSI file is deleted and the updater process exits. The scheduler returns to its normal polling loop.

Retry with cached file: When a retry fires (e.g. after a process conflict), a new updater process is spawned. If the downloaded file still exists on disk, it skips the download but repeats all integrity checks before attempting install again.


Interactive (notification-triggered) update flow

When notifications.triggers is configured, the scheduler uses WMI (__InstanceCreationEvent) to watch for the listed process names being launched — this is event-driven, not polling. When one of the trigger processes starts and a pending update exists:

1. Show the notification

The scheduler launches the Updater UI process in the user's desktop session. The UI displays a toast: "A new version of [app] is available." The notification appears when the user starts their app, before they are deep in unsaved work.

2. User presses "Update"

The UI contacts the scheduler over a named pipe and requests an update. The scheduler responds in one of two ways:

ScenarioScheduler response
A silent update is already runningReturns the existing update's session ID. The UI connects to that process and shows its progress. No duplicate process is spawned.
No update is currently runningSpawns a new updater process and returns its session ID. The UI connects and shows progress.

The UI then connects to the updater process's named pipe endpoint to receive progress updates. The updater process starts work immediately upon launch; the UI attaches and begins displaying progress as soon as the connection is established.

3. Progress display

The updater process pushes status messages to the UI over the named pipe: downloading, validating, installing. The UI renders these as a progress view (shared with the installer UI design).

4. Files-in-use prompt

If the update needs to replace files that are locked by a running application:

  • When UI is connected: The updater process pauses and sends a message to the UI asking: "These apps are using files that need to be updated. Close them or cancel?" The user sees two choices:
    • Close apps – the updater process (running as LocalSystem) terminates those apps and proceeds with installation.
    • Cancel – the updater process aborts with a user-cancelled status.
  • When no UI is connected (silent mode): The updater process exits with a ProcessConflictDetected fault. The scheduler retries after retryInterval.

5. Reboot prompt

If the MSI install signals that a Windows restart is required, the updater sends another prompt to the UI: "Restart now or later?"

  • Now – the updater triggers a Windows restart.
  • Later – the updater completes successfully; the pending reboot is deferred.

6. Notification dismissed

If the user dismisses or minimizes the notification without pressing "Update", it does not reappear during that session.


Folder structure and protection

All updater runtime data lives under %ProgramData%:

%ProgramData%\
└── <AppId>\
├── Logs\
│ ├── scheduler.log ← scheduler activity (single rolling file)
│ ├── updater-<sessionId>.log ← one per update attempt
│ └── <installerFileName>-<sessionId>.log ← MSI install log (paired with updater log)
└── Downloads\
└── <filename>.msi ← downloaded installer (deleted after successful install)

The <AppId> is the updater's application identifier (e.g. MasterPackager.Updater), configured in the INI file under [General] > Id.

Paired log files: Each update attempt produces an updater log and (if installation ran) an MSI installer log. Both share the same session GUID in their filename, making it easy to correlate what the updater decided with what happened during installation.

Folder permissions: The service creates these folders with permissions restricted to elevated users only. Even if a non-admin user account is compromised, they cannot:

  • Place a malicious MSI in the downloads folder.
  • Tamper with log files to hide evidence.
  • Modify the configuration file.

Even without folder protection, the integrity checks (checksum + signature match) would still prevent a rogue file from being installed. The folder ACLs are defence-in-depth.

Log retention: Logs older than installerLogsRetentionDays (default 30) are cleaned up automatically when the service starts.


Security model

The auto-updater is intentionally paranoid – an update channel is a privileged backdoor into every install, and a hijacked feed must not be allowed to deliver malicious code.

The defences:

  1. HTTPS only. latestVersionDescriptor.url is enforced to be https:// at build time.
  2. SHA256 verification. The hash from the feed must match the bytes downloaded.
  3. Signature pinning. The downloaded MSI must be signed by the same certificate (matching thumbprint) as the updater executable. For Azure Trusted Signing certificates (where thumbprints rotate), the updater falls back to comparing Enhanced Key Usage OIDs that identify the signing identity. Only the original vendor can push upgrades.
  4. Same-or-higher version. Downgrades are not performed silently.
  5. Per-user notifications, per-machine install. Individual users cannot accept updates that change the service binary. Only LocalSystem performs the install.

MSI auto-updater vs MSIX update flow

MSI updaterMSIX (App Installer / Store)
Where it livesA Windows service shipped in your MSIOS-level component (Microsoft.AppInstaller) or the Microsoft Store client
TriggerPolling on a schedule you configureOS-controlled, typically on user login or store refresh
Feed formatAnything – your endpoint, your regexAn .appinstaller XML file that follows a Microsoft-defined schema
Permissions to installService runs as LocalSystem, no elevation neededPer-user package, updates apply to the active user only
Per-machine install requiredyes (%ProgramFiles%)n/a
Custom UIToast on notifications.triggersBuilt-in OS UI
Best forWin32 apps with a website distribution modelApps already moving toward Microsoft Store / modern UWP-style features

If your product ships in both formats, configure msi.updater for the MSI and an .appinstaller URL for the MSIX. The two paths are independent.