Patching third-party apps on Windows with winget
Inventory, prioritise and patch third-party apps on Windows: browsers and runtimes first, winget as SYSTEM, App Installer policy, removing what you can't patch.
The patching pillar ends with a warning: much of what attackers exploit on Windows endpoints is not Windows. Browsers, PDF readers, Java and .NET runtimes, archive tools, VPN clients and remote-access software have their own update mechanisms, their own release cadences and, often, no central management at all. Windows Update client policies don't touch them.
This guide is a practical starting point for small and mid-sized estates: find what is installed, decide what matters most, and patch it with tools you already have, mainly the Windows Package Manager (winget) and vendor auto-update policies.
Step 1: inventory what is installed
You can't patch what you don't know about. If you have Microsoft Defender for Endpoint, its software inventory (in Defender Vulnerability Management) is the best source, because it maps installed versions to CVEs. Intune's Discovered apps report and Configuration Manager hardware inventory are good alternatives.
Without those, read the uninstall keys, which is what Programs and Features does. Avoid Get-CimInstance Win32_Product: querying that class triggers a consistency check of every MSI package and can start repairs.
$paths = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
Get-ItemProperty $paths -ErrorAction SilentlyContinue |
Where-Object DisplayName |
Select-Object DisplayName, DisplayVersion, Publisher, InstallDate |
Sort-Object DisplayName |
Export-Csv "C:\Temp\apps-$env:COMPUTERNAME.csv" -NoTypeInformationPer-user installs (many browsers, collaboration clients and developer tools) register under HKCU instead, and land in %LOCALAPPDATA%. They escape machine-wide inventories and are often the oldest versions on the device. Check them too, or block per-user installers with App Control.
winget can also show what it recognises and what has an update:
winget upgrade --include-unknownStep 2: prioritise by exposure
Not every application deserves the same speed. A simple three-tier model works:
| Tier | Examples | Target |
|---|---|---|
| 1 - Internet-facing content handlers | Browsers (Edge, Chrome, Firefox), PDF readers, Office add-ins, email clients, Java and .NET runtimes used by browsers or apps, archive tools (7-Zip, WinRAR) | Days; within a week for known-exploited |
| 2 - Remote access and network clients | VPN clients, remote-support tools, Zoom/Teams/Webex, SSH/FTP clients | One to two weeks |
| 3 - Everything else | Line-of-business apps, utilities, developer tools | Normal monthly cycle |
Raise any item to the top when it appears in the CISA Known Exploited Vulnerabilities catalog or your vendor's advisory says it is being exploited. Tier 1 apps parse untrusted content all day; that is where exploitation happens.
Step 3: let vendors update where they do it well
The cheapest patching is the one the application does itself. For tier 1, turn the vendor's updater on and enforce a restart window, rather than repackaging every release:
- Microsoft Edge updates itself through EdgeUpdate. Keep its update policies at the default (updates allowed) and set Notify a user that a browser restart is recommended or required (
RelaunchNotification) with a relaunch period. Details are in the Edge hardening guide. - Google Chrome has equivalent
RelaunchNotificationandRelaunchNotificationPeriodpolicies, and Google Update policies control whether updates are allowed. Use the vendor ADMX templates. - Mozilla Firefox is managed through its enterprise policies (
policies.jsonor ADMX); make sureDisableAppUpdateis not set. - .NET runtimes receive servicing through Microsoft Update if devices are allowed to get updates for other Microsoft products. In Intune update rings, that is Microsoft product updates; in Group Policy, the "Install updates for other Microsoft products" option of Configure Automatic Updates.
Check what the vendor updater does when the user lacks admin rights. Some updaters install a machine-wide service that works for everyone; others silently fail for standard users, which is exactly what you want everyone to be after removing local admin rights.
Step 4: fill the gaps with winget
For applications without a reliable self-updater, winget can detect and install updates from its repository. Interactive use is simple:
winget upgrade # list available upgrades
winget upgrade --id 7zip.7zip --silent --accept-package-agreements --accept-source-agreements
winget pin add --id Oracle.JavaRuntimeEnvironment # exclude an app that must stay on a versionFor fleet use, run it as SYSTEM from a scheduled task, an Intune remediation or your RMM. winget is part of the App Installer package and not on the SYSTEM account's PATH, so resolve the executable first:
$winget = Resolve-Path "$env:ProgramFiles\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe\winget.exe" |
Sort-Object Path | Select-Object -Last 1 -ExpandProperty Path
$approved = 'Google.Chrome', 'Mozilla.Firefox', '7zip.7zip', 'Adobe.Acrobat.Reader.64-bit'
foreach ($id in $approved) {
& $winget upgrade --id $id --exact --silent --scope machine `
--accept-package-agreements --accept-source-agreements --disable-interactivity
}Use an explicit list of approved IDs rather than winget upgrade --all. --all updates whatever winget happens to recognise, including apps whose new major version you haven't tested. The Microsoft.WinGet.Client PowerShell module (Get-WinGetPackage, Update-WinGetPackage) gives structured output if you prefer objects to parsing text.
Larger estates usually graduate to a dedicated tool: Intune Enterprise App Management (an Intune Suite capability, included in Microsoft 365 E5 since July 2026), Configuration Manager third-party software update catalogs, or a commercial patching product. The prioritisation and verification steps stay the same.
Step 5: lock down App Installer and winget
winget is also an installation channel, so control it with the App Installer policies under Computer Configuration > Policies > Administrative Templates > Windows Components > Desktop App Installer (registry: HKLM\SOFTWARE\Policies\Microsoft\Windows\AppInstaller):
| Setting | Recommended | Why |
|---|---|---|
| Enable App Installer Hash Override | Disabled | Stops users bypassing installer hash verification |
| Enable App Installer Local Manifest Files | Disabled | Blocks installing from arbitrary local manifests |
| Enable App Installer Additional Sources / Allowed Sources | Only your approved sources | Prevents adding untrusted repositories |
| Enable App Installer Microsoft Store Source | Per policy | Disable if the Store is not an approved channel |
| Enable App Installer ms-appinstaller protocol | Disabled | The ms-appinstaller: URI scheme has been abused to deliver malware; Microsoft disabled it by default in late 2023 |
These names match the current DesktopAppInstaller.admx, and Intune exposes the same settings in the DesktopAppInstaller area of the Policy CSP. Older templates lack some of them, so use the latest one. On devices where standard users should not install software at all, App Control or AppLocker is the real control; winget policy only narrows one path.
Step 6: remove what you can't patch
Every application you remove is one less update stream. Once the inventory is in place, sort it by owner and last use, and challenge anything without both:
- Unsupported versions: software past its vendor's end of life (old Java 8 builds without a support contract, legacy Adobe Reader versions, Python 2, abandoned plug-ins) gets no fixes at all. Replace or uninstall.
- Duplicates: three PDF readers or two archive tools on the same device triple the attack surface for no benefit. Standardise on one per function.
- Remote-access tools that IT didn't install (AnyDesk, TeamViewer, and similar) are both a patching problem and a common attacker persistence method. Remove them and block them with application control.
- Browser extensions and runtimes bundled with old line-of-business apps. Ask the vendor for a supported version, and isolate the app if none exists.
Uninstall with the vendor's silent uninstaller or winget uninstall --id <id> --silent, and record each removal. Removal is also the answer for software with no silent update path at all.
Verify it
Re-run the inventory and compare versions against the vendor's current release. On a single device:
winget upgrade --include-unknown # should list nothing from your approved set
Get-WinEvent -FilterHashtable @{LogName='Application'; ProviderName='MsiInstaller'; Id=1033,11707} -MaxEvents 20 |
Format-Table TimeCreated, Id, Message -WrapMSI-based installs log event 11707 (installation completed successfully) and 1033 (product installed, with its status) in the Application log from source MsiInstaller. winget's own logs are under %LOCALAPPDATA%\Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\LocalState\DiagOutputDir for the account that ran it (for SYSTEM, under the systemprofile folder).
At fleet level, track the percentage of devices on the current version of each tier 1 app, and the oldest version still present. The oldest version is the one an attacker will find.
What breaks
- Updates that need a restart of the app. Browsers download but don't apply until relaunch; without relaunch notifications, "updated" devices run the old binary for weeks.
- Major version jumps. Java, PDF editors and line-of-business plug-ins can break on major versions. Pin those and test.
- Per-user and machine installs side by side. A machine-wide update leaves an older per-user copy untouched, and the user keeps launching that one.
- winget as SYSTEM can't reach Microsoft Store source packages and fails on some per-user installers. Detect those and handle them separately.
Checklist
- Software inventory covering machine and per-user installs
- Tier 1 applications identified with patch targets in days
- Vendor auto-update enabled and relaunch notifications enforced for browsers
- .NET and other Microsoft products receive updates through Microsoft Update
- winget (or a patching tool) updating an approved list as SYSTEM
- App Installer policies: no hash override, no local manifests, approved sources only
- Unowned and end-of-life software removed
- Oldest-version report per tier 1 app reviewed monthly
Third-party patching closes the biggest gap left by Windows Update. For the Microsoft side of the process, see Windows Update policies and the rest of the patching and updates area.
Frequently asked questions
Is winget safe to use for enterprise patching?
The community repository is moderated and installers are hash-checked, but you are still trusting a public source. For production, restrict sources with the App Installer policies, disable hash override and local manifests, and consider a private REST source that contains only packages you have reviewed. Use winget for update detection and delivery, not as an unreviewed app store.
Why does winget work for me but not in a SYSTEM scheduled task?
winget is delivered as part of the App Installer package and is registered per user, so it is not on the PATH of the SYSTEM account. Call winget.exe by its full path under Program Files\WindowsApps, run with --scope machine, and accept that Microsoft Store source packages and some per-user installs are not available in that context.
Should I patch or remove old software?
Remove it whenever nobody can name an owner or a need. Every application you remove is one less update stream to track and one less exploitable component. Older Java runtimes, unused PDF tools, abandoned remote-access tools and duplicate browsers are the usual candidates. Patch what the business actually uses and keep an approved list.
Patching third-party apps on Windows with winget