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, thenwinget pin listto audit. - Chocolatey: install with an explicit
--version, then add--pinsoupgrade allskips 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.



