Winget and Chocolatey for Silent Upgrades on Windows Server: A Working Setup

Windows Server has no equivalent of a Linux distribution’s unattended-upgrade daemon, and Windows Update covers only Microsoft’s own patches. For third-party software — Git, 7-Zip, Python, Node, SQL Server tooling — you need a package manager, and the two realistic choices on Server 2019, 2022 and 2025 are winget and Chocolatey.

Both can run unattended on a schedule, both have sharp edges when run under a service account, and both will silently do the wrong thing if you point them at the wrong scope. This is a working setup rather than an overview: what to install, how to pin, how to log, and where each tool breaks.

Which tool for which job

Winget is Microsoft’s package manager, shipped with modern Windows and available as an MSIX bundle on Server 2019 onward. It resolves packages from the winget community repository, which mirrors vendor installers. Its strength is that it uses the vendor’s own installer, so licensing and signatures are exactly what the vendor intended. Its weakness is that many vendors ship interactive MSIs, and winget’s silent switches may not suppress every UI prompt.

Chocolatey wraps installs in PowerShell scripts and has a much longer history on servers. It handles silent flags per package, has a large maintained repository, and its business edition adds package internalisation — downloading the installer once, then installing from a local cache, which matters if your VPS has flaky outbound access. The community edition is free and adequate for a small fleet.

Aspect Winget Chocolatey
Install source Vendor installer via manifest PowerShell script wrapping installer
Machine scope Yes, with admin context Yes, default for admin
Pinning versions Yes, per package Yes, via --version
Offline cache Limited Business edition internalise
Server support 2019+, best on 2022/2025 2012+

Installing both without breaking each other

Install winget first. On Server 2025 it is present; on 2019 and 2022 you add it via the App Installer MSIX bundle, which requires the Desktop Experience — winget does not run on Server Core. Chocolatey installs from a one-line PowerShell bootstrap and places its binaries in C:\ProgramData\chocolatey\bin, which is already on the machine PATH.

# AllUsers scope, non-interactive
$env:ChocolateyInstall = 'C:\ProgramData\chocolatey'
Set-ExecutionPolicy Bypass -Scope Process -Force
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
iex ((New-Object Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

choco --version
winget --version

Keep the two package sets disjoint. Installing the same application through both managers leads to a state where each thinks it owns the install and upgrades fight over the same files. Pick one manager per application and record the choice in a short table in your runbook.

Unattended upgrade patterns that actually work

Winget’s upgrade verb is the simplest option and covers everything installed through it:

winget upgrade --all --silent --accept-package-agreements --accept-source-agreements --disable-interactivity

Chocolatey’s equivalent upgrades only packages it manages, and needs -y to avoid prompts:

choco upgrade all -y --no-progress --limit-output --execution-timeout=2700

Run both from a scheduled task as SYSTEM, not as your interactive user, so the machine-scope registry and Program Files are writable and the job does not depend on anyone being logged in. Log to a file with timestamps, because “the upgrade ran” and “the upgrade succeeded” are different claims.

Pinning, exclusions and rollback

Blindly upgrading everything is how a working box breaks at 2 a.m. Pin anything whose major version you have not tested:

  • Winget: winget pin add --id Git.Git --version 2.45.2, then winget pin list to audit.
  • Chocolatey: install with an explicit --version, then add --pin so upgrade all skips it.
  • Exclude packages that need a reboot mid-upgrade from the same run as those that do not.

Rollback is the weak spot in both tools. Winget has no downgrade verb; you reinstall the pinned older version explicitly. Chocolatey can install an older version but will not restore prior configuration. The practical answer is to snapshot the VM before a bulk upgrade window, or to keep the installer binaries in a local folder so you can reinstall a known-good build without relying on the repository still hosting it.

Running under a service account and logging

A dedicated gMSA or a local service account with “Log on as a service” is the right identity. SYSTEM works but has unrestricted local admin, which is more than a package manager needs. If you use a proxy, both tools need it configured separately — winget honours the WinHTTP proxy, Chocolatey uses choco config set proxy.

New-Item -ItemType Directory -Force C:\logs\pkg
$log = "C:\logs\pkg\upgrade-$(Get-Date -f yyyyMMdd-HHmm).log"
Start-Transcript -Path $log
winget upgrade --all --silent --accept-package-agreements --accept-source-agreements --disable-interactivity
choco upgrade all -y --no-progress
Stop-Transcript
Get-Content $log | Select-String -Pattern 'error|failed|exit code'

Parse the transcript for failures rather than relying on exit codes alone: both tools return 0 in cases where an individual package failed. Alert on the string match, and keep 30 days of logs on a separate volume so a disk-full condition does not erase the evidence.

The traps worth knowing before you schedule anything

Interactive MSIs. Some vendor installers ignore silent flags and wait for a click. Set --execution-timeout in Chocolatey and a task-level timeout in the scheduler so a hung installer does not block the queue.

Per-user versus machine scope. A package installed in your RDP session’s user context lands in %LOCALAPPDATA% and is invisible to a SYSTEM-scope upgrade. Always install with admin elevation and machine scope; verify with winget list --scope machine.

Proxy and TLS. A proxy that inspects TLS can break manifest signature checks. Whitelist the repository endpoints rather than disabling validation.

Reboots. Neither tool reboots for you reliably. Detect pending reboot with the registry keys under Component Based Servicing and schedule the restart yourself inside a maintenance window. For the wider patching picture on a rented box, see our notes on Windows Server patch management on a VPS; if you are still choosing a host, the Windows VPS buyer’s checklist covers image and snapshot behaviour, which is what makes rollback practical.

Leave a Comment