Systems Admin

How to Install Windows Updates with PowerShell

Introduction

Updating one Windows machine through Settings > Windows Update is fine. Updating fifty servers that way is not. The minute you have more than a handful of systems — or any production server you cannot remote-desktop into during business hours — you want a scriptable way to drive Windows Update from a single PowerShell window.

The community module PSWindowsUpdate wraps the Windows Update Agent COM API behind clean cmdlets that work the way every other PowerShell module does: parameters, pipelines, and remote execution against a list of computer names. In this article you will learn how to install PSWindowsUpdate, what it gives you, and how to use it to query and install updates on a single machine, a fixed list of remote machines, or every computer in a chosen Active Directory OU.

Install PSWindowsUpdate

Three commands install the module from the PowerShell Gallery. Run them once per machine where you want to manage updates locally; for remote operation you also need the module on the target machines.

Step 1 — Set the Execution Policy

By default Windows refuses to run scripts downloaded from the internet. Open Windows PowerShell as administrator and run:

Set-ExecutionPolicy RemoteSigned -Force

This allows scripts you authored locally to run unsigned, while still requiring downloaded scripts to be signed by a trusted publisher. Close and re-open the elevated PowerShell window after running this command so the new policy takes effect for the new session.

Step 2 — Install / Update PowerShellGet

PowerShellGet is the package manager that talks to the PowerShell Gallery. Refresh it to the current version so it can install other Gallery modules cleanly:

Install-Module PowerShellGet -Force

The first time you run this on a new system it will prompt to install the NuGet provider — press Y and Enter to continue. Subsequent runs just update PowerShellGet itself.

Step 3 — Install PSWindowsUpdate

Install-Module -Name PSWindowsUpdate -Force

That is it — the module installs to the AllUsers scope under C:\Program Files\WindowsPowerShell\Modules\PSWindowsUpdate\ and is now available in any new PowerShell session.

Article opening titled 'How to Install Windows Updates with PowerShell' showing the three setup steps (Set-ExecutionPolicy RemoteSigned -Force, Install-Module PowerShellGet -Force, Install-Module -Name PSWindowsUpdate -Force) followed by a Get-Command -Module PSWindowsUpdate output table listing the alias and cmdlet members of the module: Clear-WUJob, Download-WindowsUpdate, Get-WUInstall, Get-WUList, Hide-WindowsUpdate, Install-WindowsUpdate, Show-WindowsUpdate, UnHide-WindowsUpdate, Uninstall-WindowsUpdate, Add-WUServiceManager, Enable-WURemoting, Get-WindowsUpdate, Get-WUApiVersion all at version 2.2.1.5
Three commands set up PSWindowsUpdate; Get-Command -Module PSWindowsUpdate lists the aliases and cmdlets the module exposes

Explore the PSWindowsUpdate Cmdlets

List every cmdlet and alias the module exposes:

Get-Command -Module PSWindowsUpdate

The output is a long list, but the cmdlets you will actually use are a small subset:

  • Get-WindowsUpdate — query available updates (also installs when given -Install).
  • Install-WindowsUpdate — alias for Get-WindowsUpdate -Install.
  • Hide-WindowsUpdate / Show-WindowsUpdate — suppress or unsuppress a specific KB.
  • Uninstall-WindowsUpdate — roll back an installed update.
  • Get-WUHistory — show the full update install history.
  • Get-WURebootStatus — check whether a pending reboot is required.
  • Add-WUServiceManager / Get-WUServiceManager — manage the update sources (Microsoft Update, WSUS, etc.).

The aliases Get-WUInstall, Get-WUList, and Install-WindowsUpdate all map back to Get-WindowsUpdate with different switches; pick whichever reads best in your scripts.

Bottom of the cmdlet list showing Get-WUHistory, Get-WUInstallerStatus, Get-WUJob, Get-WULastResults, Get-WUOfflineMSU, Get-WURebootStatus, Get-WUServiceManager, Get-WUSettings, Invoke-WUJob, Remove-WindowsUpdate, Remove-WUServiceManager, Reset-WUComponents, Set-PSWUSettings, Set-WUSettings, Update-WUModule (all at version 2.2.1.5), followed by the 'Find Windows Updates' section showing the Get-WindowsUpdate cmdlet with -ComputerName parameter, a  = @() array of three DC names, and a foreach loop calling Get-WindowsUpdate -ComputerName  -AcceptAll
Find available Windows Updates locally with Get-WindowsUpdate, on a remote system with -ComputerName, or on a fleet by looping a array through foreach

Find Available Updates

On the Local Machine

Show every update Windows Update considers applicable to the local machine:

Get-WindowsUpdate

The output is a table with KB numbers, titles, sizes, and categories. Nothing is downloaded or installed — this is a query only.

On a Remote Machine

Use -ComputerName to inspect another system. The remote machine must have PSWindowsUpdate installed and PowerShell Remoting enabled:

Get-WindowsUpdate -ComputerName "DC02-2022"

On a Fleet of Machines

Loop over a hard-coded array of names:

# List of computer names or IP addresses
$computers = @(
    "DC01-2022",
    "DC02-2022",
    "DC03-2022"
)

# Loop through each computer and run Get-WindowsUpdate
foreach ($computer in $computers) {
    Get-WindowsUpdate -ComputerName $computer -AcceptAll
}

-AcceptAll just suppresses the per-update confirmation prompt that Get-WindowsUpdate issues when piped through certain modes; it does not install anything by itself.

Install Updates

Install on the Local Machine

Three patterns are common, distinguished by their reboot behavior:

# Find available updates on the local system and install them, rebooting if required
Get-WindowsUpdate -Install

# Install all available updates without rebooting (you reboot manually later)
Get-WindowsUpdate -AcceptAll -Install -IgnoreReboot

# Install everything and let the cmdlet reboot when finished
Get-WindowsUpdate -Install -AcceptAll -AutoReboot

Use -IgnoreReboot for production systems that need a maintenance window to reboot. Use -AutoReboot for unattended overnight patch runs.

Install on Remote Machines

Same pattern as the query, with the install switches added. The PSWindowsUpdate module must already be installed on every target machine.

# List of computer names or IP addresses
$computers = @(
    "DC01-2022",
    "DC02-2022",
    "DC03-2022"
)

# Loop through each computer, install updates, and reboot
foreach ($computer in $computers) {
    Get-WindowsUpdate -ComputerName $computer -Install -AcceptAll -AutoReboot
}

Sequencing matters here — this loop hits the machines one at a time, which is what you want for Domain Controllers (you do not want all DCs rebooting at once). For non-critical fleets, you can parallelize with ForEach-Object -Parallel in PowerShell 7+ if patching speed matters more than ordered availability.

The Install Windows Updates on remote systems section showing two PowerShell snippets: a foreach loop iterating an explicit  array of DC names calling Get-WindowsUpdate -ComputerName  -Install -AcceptAll -AutoReboot, and a longer snippet that pulls the computer list dynamically from an OU (Get-ADComputer -Filter * -SearchBase  | Select-Object -ExpandProperty Name) before running the same Get-WindowsUpdate -Install -AcceptAll -AutoReboot loop
Install updates fleet-wide either by hard-coding a array or by populating it from an OU via Get-ADComputer -SearchBase + Select-Object -ExpandProperty Name

Install on Every Machine in an OU

The most useful pattern in a real Active Directory: pull the computer list dynamically from an OU and patch every member. No hand-maintained list to drift out of sync.

# Specify the distinguished name of the OU
$ouDN = "OU=Computers,OU=Company,DC=exoip,DC=local"

# Get the list of computer names in the specified OU
$computers = Get-ADComputer -Filter * -SearchBase $ouDN |
             Select-Object -ExpandProperty Name

# Loop through each computer, install updates, and reboot
foreach ($computer in $computers) {
    Get-WindowsUpdate -ComputerName $computer -Install -AcceptAll -AutoReboot
}

Combine this with separate OUs per patch ring (OU=Servers-Ring1, OU=Servers-Ring2, etc.) and you have a working patch-rollout pipeline driven entirely from AD organizational unit membership.

Operational Tips

  • Always test in a lab first. Run the loop against one machine in a non-production OU before pointing it at OU=Domain Controllers.
  • Use a maintenance-window scope. Wrap the loop in a check that the current time is inside your patching window, so an accidental kick-off in business hours does not reboot every server immediately.
  • Watch for reboot loops. A few cumulative updates require two reboots to fully apply. Run Get-WURebootStatus after the loop and re-run if any machine still reports pending.
  • Log to a file. Wrap the loop in Start-Transcript/Stop-Transcript so you have a written record of which KB applied to which machine on which date — this is the only audit trail you will want when something breaks the day after patching.
  • Filter to security only. For a stricter rollout, add -Category 'Security Updates' to install only security-classified updates and leave the cumulative/feature updates for a later pass.
  • WSUS-aware shops. If the targets get their updates from WSUS, the same cmdlets work — PSWindowsUpdate honors the configured Windows Update source. Get-WUServiceManager shows which source is in use; Add-WUServiceManager -ServiceID can switch to Microsoft Update for the next run.

Conclusion

You learned how to install the PSWindowsUpdate module and how to use it to drive Windows Update from a single PowerShell window. The recipe scales from one machine to a whole AD OU without changing the underlying cmdlet:

  1. Set the execution policy, install PowerShellGet, then PSWindowsUpdate — three commands.
  2. Get-WindowsUpdate for the local query, -ComputerName for remote, a foreach loop for fleets.
  3. Add -Install -AcceptAll -AutoReboot to actually patch, with -IgnoreReboot when you want to control the reboot manually.
  4. Pull computer names from an OU with Get-ADComputer -SearchBase for dynamic, AD-driven patch rollout.

From now on, the answer to “how do I patch fifty servers tonight?” is one PowerShell window and a foreach loop, not fifty RDP sessions.

Leave a Reply