Automating Windows Server Updates Part 2: PowerShell

Automating Windows Server Updates Part 1: Sconfig

Automating Windows Server Updates Part 3: Scheduling the Task 

Windows updates can be a blessing and a curse. On the one hand, it’s great that Microsoft is proactive in fixing issues with their operating system. On the other hand many of the issues with their operating system come from botched Windows Updates. Like deleting your files, for example:

Another annoying thing about Windows Updates is that they often require a reboot and a long time watching percentages slowly rise (Often we find ourselves staring at 100% complete for a half an hour). This is especially bad when dealing with production servers that can only be rebooted on a Sunday.

Windows does have a built-in scheduling for installing Windows Updates, but it often just doesn’t work and you don’t have much flexibility about the timing of when things end up happening. In the newest version of Windows 10 you can delay updates for up to a week, but that’s it. Working hours can be set so the thing doesn’t reboot during the day, but there are limits to that, too.

Another, more fun way to handle Windows Updates is, of course, PowerShell! In this article we are going to learn how to use PowerShell to install Windows Updates and in the next article we will use Task Scheduler to run the script on Sunday afternoon when no one is at work.

(See my previous post for instructions on setting Windows Updates to manual only with Sconfig. Keep in mind Sconfig is only for Windows Server, not Windows 10.)

Installing the Windows Update PowerShell Module

First we will need to download the PowerShell module that controls Windows Updates. Download the required module here: tp://
It’s small so it won’t take long.

Unzip the file to C:\Windows\System32\WindowsPowerShell\v1.0\Modules\ and then open PowerShell as an administrator (Right-click to find that option). I like to use PowerShell ISE because it’s got the nice “script pane” built in so you can copy and paste my examples in there and modify them to suit your environment.

To make sure it installed correctly and to see what new functions we have run:

Get-Command –module PSWindowsUpdate

If you get an error like: ” FullyQualifiedErrorId : CommandNotFoundException Get-WUInstall : The term ‘Get-WUInstall’ is not recognized as the name of a cmdlet, function, script file, or operable program” then run this:

Import-Module PSWindowsUpdate

This next command will list all of the Windows Updates you can install on your computer, but does not install them.

–WindowsUpdate –ListOnly

You may know that in the Settings GUI version of Windows Update you can use Windows Update to get updates for other things besides Windows, like Microsoft Office. You can do that with PowerShell, too! It just requires one extra step in the initial setup.

The command for the wider search of Microsoft (as opposed to Windows) Updates is:

Get-WUInstall –MicrosoftUpdate –ListOnly

If you run that one now you will get an error:

Luckily, this is easy to fix. Just run this to register the proper service:

Add-WUServiceManager -ServiceID

Now run Get-WUInstall –MicrosoftUpdate –ListOnly again:

As you can see, I now have an update for Silverlight in addition to the Windows Defender updates.

Installing The Updates With PowerShell

Now that you’ve seen what updates are ready to install you can install them simply by running:

Get-WUInstall –MicrosoftUpdate

You will get a popup asking for permission to install the update:

You can click “Yes” or “No” for each indvidual update or click “Yes to All” to install all of them from the first popup. Another approach would be to run this so you don’t have to approve them and they will just install:

Get-WUInstall –MicrosoftUpdate –AcceptAll

You can even add -AutoReboot at the end to have the server automatically reboot after installing the updates if required to do so. This is what we will be doing in our scheduled task so we don’t have to remote in to the server on a Sunday when we’d rather be at the beach:

Get-WUInstall –MicrosoftUpdate –AcceptAll –AutoReboot

This what it will look like as it does its thing. Notice the message displayed above the code window as it goes through the steps of Accepted, Downloaded, and Installed:

And when it’s finished installing it will look like this (assuming everything installed correctly):

There is a chance that an update could fail. If one does you will get output like:

4 Failed                63 KB Microsoft driver update for MS Publisher 

If you have an update that repeatedly fails to install you could download it from the Microsoft Update Catalog ( ) and install it manually or you could disable installing the one specific update if you decide you don’t need it.

Disabling Specific Windows Updates

One of the other useful commands is Get-WUHistory. This will show you all of the Windows Updates that installed on the computer, their KB, and the date and time of installation. This is handy for finding updates that broke your computer and need to be uninstalled. You can always Google the KB to find out exactly what the update entails.

If you find one that you want to uninstall, here’s how to do it (replace the KB with the one you want to uninstall):

Get-WUUninstall -KBArticleID KB4501375

Sometimes the KB isn’t listed so you have to use the title. Here is a way to disable an update easily assuming it’s the only update left:

$u = Get-WUInstall –WindowsUpdate –ListOnly
$t = $u.title
Hide-WUUpdate –title $t –MicrosoftUpdate –Confirm:$false

To keep Windows from installing that update again you will have to “hide” it or it will install it again later:

 Hide-WUUpdate –KBArticleID KB4501375–MicrosoftUpdate –Confirm:$false

If you change your mind and want to “un-hide” an update:

Hide-WUUpdate -KBArticleID KB4501375-hidestatus:$false

The PowerShell Script

Ok, lets build our script that we want the task to run for us. I’ll give you the whole thing, then break it down into its parts.

$file = "PathToTranscriptFile"  
$from = ""
$to = ""
$subject = "Windows Update Report"
$smtp = ""
Start-Transcript -path $file
Get-WUInstall –MicrosoftUpdate –AcceptAll –AutoReboot
#Get-WUInstall –MicrosoftUpdate –ListOnly
$body = [IO.File]::ReadAllText($file)
send-mailmessage -from "$from" -to "$to" -subject "$subject" -smtpserver "$smtp" -body "$body"

You can copy and paste this into a text editor and then change the variables in bold to values that make sense for your environment. Save the text file with a .ps1 file extension.

If you don’t need the details of the script explained you can skip to the next section.

$file = "PathToTranscriptFile"  
$from = ""
$to = ""
$subject = "Windows Update Report"
$smtp = ""

Anything beginning with a dollar sign ($) is a variable in PowerShell. The ones above are our email settings. PowerShell will need to know how to send the email so you will need to swap out your values for the parts in bold.

$file = "PathToTranscriptFile" 

This variable stores the path to the transcript file to simplify adding it into the body of the email.

Start-Transcript -path $file

Start-Transcript does pretty much what you’d think: it saves what happens in the PowerShell window to a file. This is how we’re going to harvest the status of the Windows Updates so we know what got installed.

Get-WUInstall –MicrosoftUpdate –AcceptAll –AutoReboot

This is the command we learned in the last post. It installs all of the available Windows Updates and reboots the computer if necessary.

#Get-WUInstall –MicrosoftUpdate –ListOnly

This line with the “#” in front of it will not run. The “#” tells PowerShell to ignore the line and go to the next line. I have this line in here for testing purposes. When I only want to get an email about the available updates, but I don’t want to install them (and I DEFINITELY don’t want to reboot the server) I will move the “#” up one line to expose this test line and hide the one that does the real update. You might want this line for initial testing just in case the email doesn’t work how you need it to at first. When you get everything how you like it you can move the “#” back down a line.


Then we stop the transcript so we can get the file the transcript created and put it in the body of an email.

$server = $env:COMPUTERNAME

In this line we are creating a variable that holds the name of the server we are running the Windows Updates on. The server name is only useful if you are running this script on multiple computers, which I am.

$env is basically a list of variables that you can use to get (or set) information about your computer. You can run Get-ChildItem Env: to see a list of all of the Environment variables. COMPUTERNAME is the name of the computer, of course, and using the Environment Variable for it enables us to use this same script on any computer; we don’t need to supply the computer’s name because the script gets it for us at runtime!

$body = [IO.File]::ReadAllText($file)

The $body variable reads the $file variable that has our Update info and stores it to use in our email alert.

send-mailmessage -from "" -to "" -subject "Windows Update Report" -smtpserver "" -body "$body"

Finally, we send the email alert. Send-mailmessage is the commandlet that sends an email. It requires a sending email address, a destination email address, a subject line, an email server and the body of the email which contains the details of our Windows Updates.

You can test this script by opening PowerShell ISE as an administrator and loading the script from “File” > “Open” or the folder icon.
Don’t forget to move the “#” up to the -AutoReboot line if you don’t actually want to install and reboot the server. Press the green “play” icon to run the script.

If everything was done correctly you should get an email that looks like this:

In the next post I will show you how to set up a scheduled task that will run Windows Updates every Sunday afternoon.

Automating Windows Server Updates Part 3: Scheduling the Task 

Leave a Reply

Your email address will not be published.