Windows Updates PowerShell Script - 夜莺博客

Windows Updates PowerShell Script

原文:Windows Updates PowerShell Script — theDXT (Daniel Keer)

There have been a lot of critical exploits over the last few months. Really the best way to deal with that is Windows Updates. Now I can hear you complaining that Windows Updates left untamed will just reboot your servers randomly or I don’t want to build WSUS or my RMM doesn’t patch well and it sucks and .

Well I’ve created a PowerShell script that I called DK Win Updates that will help solve the issue. It uses the Windows Update Agent API to search for updates and guess what you can run this as .ps1 file, you could build a scheduled task to run it, you can toss it in your RMM and run it as a script. (if your RMM can’t do that, you should find a new RMM).

The script will search for Windows Updates as if you were clicking on the Windows Check for updates UI button. It will not download driver updates because I’m not that crazy. Do that yourself or tweak the script to make it do it (but I wouldn’t).

Once the script finds updates it will list out all the updates it found and then it will start downloading them and then it will move onto installing them.

Image 1
After the updates are installed if the updates need a reboot it will reboot the system and give a 5 min warning before rebooting.

Image 2

A logged in user would see this if they ignored your emails about Windows Updates

I’ve only tested this on Windows 10, Windows Server 2016, and Windows Server 2019. It might work on older versions of Windows it might not. You should really upgrade.

Why the Windows Update UI Is Not Enough

Unpatched Windows is the single easiest way into a network, and the reason is not that patching is hard — it is that the built-in update mechanism is designed for interactive users, not for fleets. A workstation that is off at patch time, a server where an admin keeps clicking "later", a build where the automatic update service has been disabled by a tuning script someone wrote in 2016: all of these end the month unpatched while the dashboard still shows a green tick because the machine checked in. The gap between "the update exists" and "the update is installed everywhere" is the gap attackers live in.

The usual fixes all have a cliff. WSUS works, until you inherit a shop where nobody wants to run a server for it. Group Policy works, until you discover half the fleet is off-domain or the client-side targeting is a mess. Commercial RMM and MDM agents work well but cost money per endpoint and take weeks to roll out. What is missing in a lot of small and mid-size environments is a simple, scriptable, dependency-free way to say "go install the approved updates now, and reboot if you have to."

That is exactly the problem this script was written to solve. It talks to the Windows Update Agent (WUA) COM API that Windows already ships, it runs on any Windows 10 or Server 2016/2019 build without installing anything, and it can be dropped into whatever scheduling mechanism you already have — Task Scheduler, a startup script, an RMM, or an Ansible task that pushes the file and runs it.

What the Script Actually Does

Under the hood the script uses the same engine as the Settings app. It creates a Windows Update session with New-Object -ComObject Microsoft.Update.Session, then a searcher with Microsoft.Update.Searcher, and asks it for everything that is not hidden, not already installed, and not a driver. The search string excludes driver updates deliberately: driver packages vary between hardware revisions of the same model, a bad display or storage driver can brick a machine on reboot, and there is rarely any reason to push drivers from a script rather than the OEM tooling. The script also filters out updates the user has hidden, so you keep the ability to suppress a problem package.

The lifecycle it drives is the standard four steps: search, download, install, reboot. The search results are written to the console so the log shows exactly which KBs were selected before anything changes. The download phase pulls the payloads into the local update cache, and the install phase applies them. Nothing happens to the machine's configuration or files other than the updates themselves.

Two behaviours are worth calling out because they trip people up. First, the script cannot detect or install Windows 10 feature updates (the version upgrades, e.g. 21H2 to 22H2); those are separate packages served by a different API and are best handled by a servicing tool. Second, it does not honour a WSUS "approved only" policy in the way a domain-managed client does — if the machine points at WSUS, the search still runs against that WSUS server's catalogue, so the updates you get are the ones WSUS offers, not Microsoft's full catalogue. That is usually the behaviour you want in a domain, but it is worth knowing.

How to Run It

Download the script and run it from an elevated PowerShell prompt:

# interactive run, elevated
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force
.\DKWinUpdates.ps1

For a fleet, the more useful pattern is to run it through your existing remote tooling rather than interactively. With PowerShell Remoting it is one line per machine:

Invoke-Command -ComputerName SRV01,SRV02 -FilePath .\DKWinUpdates.ps1

With PsExec, for a machine where WinRM is not enabled:

psexec \\SRV01 -s -h powershell.exe -ExecutionPolicy Bypass -File C:\temp\DKWinUpdates.ps1

The -s flag runs it as the SYSTEM account, which is what the WUA API expects when there is no interactive user logged in, and -h makes the resulting window visible if a session exists. If your RMM can push and execute arbitrary scripts, do that instead — it gives you per-machine result capture and scheduling for free, which is the whole reason you have an RMM.

Scheduling It with Task Scheduler

For a single server or a small pool, a scheduled task is the least-moving-parts option. Create one task per machine (or deploy a task via GPO), trigger it on whatever cadence matches your risk appetite — weekly during a low-traffic window is the common choice — and run it as SYSTEM with highest privileges. The exact wizard steps matter less than three settings:

  • Run whether the user is logged on or not, so it survives a locked console.
  • Do not enable "Stop the task if it runs for longer than", or raise the limit generously — a large cumulative update can legitimately take 20 minutes.
  • Set the task to not start a second instance if one is still running.

If a reboot is required, the script announces it and gives the logged-in user a five-minute warning before restarting. If you would rather never reboot automatically, split the script's responsibility and write a wrapper that calls the search and install phases and skips the reboot, then let your normal maintenance-window process handle restarts. The trade-off is honest: an update that installs but never reboots can leave a machine in a state where the patch is staged but not active, which is a different kind of unpatched.

What a Logged-In User Sees

Depending on how they have tuned their notifications, a user at the console sees the standard Windows Update experience: progress notifications as packages download and install, and then the reboot warning if one is required. The second screenshot in this article is exactly that rebuild-countdown prompt. A user who ignored the email telling them about the maintenance window gets the same treatment as anyone who tried to install updates from the Settings app, which means there are no surprises about the machine restarting while they are working — as long as the warning is respected.

Things to Be Aware Of

A few things to know before you roll this out across a fleet:

  • The script can’t detect / install Windows 10 Feature Updates / Upgrades. Version upgrades are a separate, heavier process; use your servicing tooling for those.
  • The Windows Updates history in Windows settings won’t show the fact that the script has installed the updates, but if you look in Programs and Features > Installed Updates they will show up. They also show in event viewer. If your compliance reporting reads only the Settings history, it will under-report; read the event log or the WUA inventory instead.
  • It may install a preview update but only if the preview update would normally be available if you clicked check for updates in the normal Windows UI. If your organisation avoids preview patches, suppress them at the WSUS or policy level rather than relying on the script to filter them.
  • It has only been tested on Windows 10, Windows Server 2016 and Windows Server 2019. It may work on older builds; it may not. Upgrade rather than debugging old PowerShell and old WUA behaviour.
  • Run it elevated. A non-elevated session can search but the install phase will fail with an access-denied error that looks like a broken script.

How It Compares with WSUS, Intune and PSWindowsUpdate

If you already run a patch management stack, use it — this script is not trying to replace WSUS, Configuration Manager or Intune, and it has no reporting, no approval workflow and no ring deployment. Where it earns its place is as a gap-filler: workgroup machines, appliances that only accept a scheduled task, lab systems, and the long tail of machines that somehow fell out of the managed population. PSWindowsUpdate, a well-known community module, does overlap; the difference is that this script has no external dependency and can be dropped on a machine that cannot reach the PowerShell Gallery. Pick whichever your environment can actually deliver reliably, and be honest that the best patch system is the one that runs on every machine you own.

Related Reading on This Site

If you manage the Windows side alongside virtual infrastructure, see Enable Windows 10 Extended Security Updates for staying patched past end of support, iDRAC Redfish API automation with Python and PowerShell for scripted hardware management, and Veeam Backup & Replication 13 Windows install for the backup layer that should exist before any patch rollout.

Download

I plan to add more features to it in the future like better verbose output about what its downloading and what its installing and also sending that to a log output file.

The script can be downloaded from my GitHub https://github.com/thedxt/win-updates