How to manage Windows Updates using Powershell

Patch Management in our days is one of the most important tasks for the IT for small ,medium or large organizations.
Unfortunately to be honest it’s very time consuming and sometimes very complex task.

For these reasons lot of IT don’t give the attention that must be has the Patch Management. This is what hackers take advantage to exploit the systems most of the times.
I wrote articles in the past related with WSUS that can read if not.

How to install & configure WSUS in Windows Server 2016

WSUS Best Practices on Windows Server 2016

I understand that some of you maybe don’t have the time , budget or for any other reason to install and manage WSUS.

So today i will explain how can Manage Windows Updates in the Workstations or Servers with Powershell

I am sure that some of you have here for the module PSWindowsUpdate created by Michal Gajda.

Before start You can find the module in PowershellGallery

The only prerequisites is to have Windows OS from Windows 7 or Windows Server 2012 or later and Powershell v.2.0 and later.

So Let's start

 

How to install the PsWindowsUpdate module

The installation of the PsWIndowsUpdate module it's simple but the steps are different when you  have Windows Server 2016/Windows 10 and later or Windows Server 2012R2/Windows 8.1and prior.

I created different sections base on the Windows OS to describe exactly the steps that you should follow. 

 

Local Installation In Windows Server 2016/Windows 10 and later

The installation of the PsWIndowsUpdate module in a local Server/Workstation it's not require any advance knowledge when you have Windows Server 2016/Windows 10 and later.

  • Decide which Server/Workstation you want to install and use the PSWindowsUpdate module.

  • Open a Powershell As administrator and run the following command to install the module.

  • Type Y in the question regarding the Untrusted respository

    Install-Module -Name PSWindowsUpdate
Install Powershell Module

 

  • After finish the installation don't wait to see any info.
  • To verify that the module installed type the following command to see all the available commands of the module.
    Get-Command -Module PSWindowsUpdate
Get-Command for PsWindowsUpdate powershell module

 

 

Local installation prior to Windows Server 2016/Windows 10

Windows OS prior to Windows Server 2016 or Windows 10 it's not include the Install-module command in Powershell.

So if you have Windows Server 2012/Windows 8.1 it needs more steps to install the PSWindowsUpdate module

  • First of all you must download the module manual from the PowershellGallery .
  • Save it in a folder to use it later.
  • Unzip the file pswindowsupdate.2.2.0.2.nupkg (version depends when you will download).
  • Now you can see a folder with a name pswindowsupdate.2.2.0.2.
  • Open a Powershell As administrator.
  • Change the path in the folder that you have save and extracted the module
  • Run the following command
    Import-Module PSWindowsUpdate.psd1
  • Now run the Get-Command -Module PSWindowsUpdate to identify that you have import the module and have the available commands.

 

Remotely installation In Windows Server 2016/Windows 10 and later

With the  PsWindowsUpdate module you can install Windows Update remotely in Servers/Workstations in order to centralize the deployment of the Windows Updates when you don't have the WSUS.

The only prerequisite is to enable the TLS1.2 security protocol in powershell to be able download and install the Nuget Package Provider that requested before install the Pswindowsupdate module.

By default Powershell use the Ssl3 and Tls as Security Protocols. 

Nuget.org has remove the security protocols Tls1.0 and Tls1.2 from 2020 as you can read in Deprecating TLS 1.0 and 1.1 on NuGet.org

So as I love the automation I have create a simple script that do the followings in order to install the module in the Remote Servers/Workstations.

  • Create a new PSsession
  • Enable the TLS12 Protocol
  • Install the PsWindowsupdate module
  • Get the Windows Updates that must be install
  • Close the PSSession

------------------------------------------------------------------------------------------------------------------

$session=New-PSSession -ComputerName <yourcomputername>  -Credential "credential of admin account"
Invoke-Command -Session $session  -ScriptBlock {
[Net.servicepointmanager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12
Install-module pswindowsupdate -force -AllowClobber
Get-WindowsUpdate | Format-Table

Get-PSSession | Remove-PSSession 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

Remotely installation prior to Windows Server 2016/Windows 10

The installation of the module in Windows Server 2012/Windows 8.1 and prior remotely require more steps included some challenges that must be resolve.

Following the steps you can proceed to resolve any challenge and install the module.

  • First of all you must save the folder pswindowsupdate.2.2.0.2 that you have extracted in a share location that can has access from the Servers/workstations that you want to install the module.
  • Because the module will be located in a share location if you try to run an Import-module in Invoke-command in the remote servers/workstation you will get an Access denied error. The reason is that  with the Invoke-command it's a second hop and the remote computer can't delegate the credentials from your computer to get access in the UNC path.

 

  • To be able to resolve this challenge must enable the WSMAN CredSSP to transfer the credentials over the network and allow us in remote server/workstation to get access in the remote location that the module was saved. This is security issue but with the following script will be enable the WSMAN CredSSP only the time that needs to Import the module and after that will be disable it again.
  • The steps are lot so I create a script that can do it for you and stay safe as describe above the WSMAN CredSSP will be enable only for the time that needs to import the module 
  • The following script is an example only for 2 Servers and do the following
    • Enable WSMAN CredSSP in Client Role in the Server/Workstation that you will use it to install remotely the module in other devices
    • Create a new PSSessionfor every Server/Workstation
    • Enable WSMAN CredSSP as Server Role to accept the credentials in remote Servers/Workstations
    • Remove the PSSession
    • Create a new PSSessionwith Authentication method CredSSP in every remote Servers/Workstation in the list
    • Import the PSWindowsUpdate module from the share location
    • Get the Windows Updates that must be install
    • Disable the WSMAN CredSSP in every remote device
    • Disable the WSMAN CredSSP in the Server/Workstation that run the Powershell
    • Close the PSSession

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Enable-WSManCredSSP -Role Client -DelegateComputer computernames -Force
$session1,$session2=New-PSSession -ComputerName computernames
Invoke-Command -Session $session1,$session2  -ScriptBlock { 
Enable-WSManCredSSP -Role Server -Force 
}
Get-PSSession | Remove-PSSession 

$session=New-PSSession -ComputerName computernames -Authentication Credssp -Credential "credential of admin account"
Invoke-Command -Session $session  -ScriptBlock { 
Import-Module  "share path of the PSWindowsUpdate.psd1"
Get-WindowsUpdate | Format-Table
Disable-WSManCredSSP -Role Server

Disable-WSManCredSSP -Role Client
Get-PSSession | Remove-PSSession 

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

How to install Windows Updates with PSWindowsUpdate module

The installation in a local Server/Workstation of the Windows Updates with the PSWindowsUpdate module it's the same for every Windows OS.

  • You can write down the following command to get all the available powershell commands that you can use in the module
    Get-Command -Module PSWindowsUpdate
  • I will not explain all the commands in this article but only that we need to use.
Get-Command for PsWindowsUpdate powershell module

 

  • So in order to get the available Windows Updates of the Server/Workstation  you can run the following command
    Get-WindowsUpdates
  • After some time you can see the list of the available Windows Updates.
Get Windows Updates powershell command

 

  • You have the option to install all the Available Windows updates with the following command
    Get-WUInstall -AcceptAll -AutoReboot or Get-WUInstall -AcceptAll -IgnoreReboot
  • Or if you want to install only specific Windows Updates you can run the following command.
  • Let's install only the Windows Malicious Software Removal tool x64 update in my PC
    Get-WUInstall  -KBArticleID KB890830   -AcceptAll

 

  • These are some of the most common commands that will be use in this module.

 

How to install Windows Updates Remotely in Windows Server 2016/Windows 10 and later

As we have already create the script to install the PSWindowsUpdate module the only thing that must change is the line 

Get-WindowsUpdates with the Get-WUInstall.

How to use the Get-WUInstall depends from you.

  • if we want to install all the Updates or not.
  • If you want to restart the Server/Workstation or not

------------------------------------------------------------------------------------------------------------------

$session=New-PSSession -ComputerName <yourcomputername>  -Credential "credential of admin account"
Invoke-Command -Session $session  -ScriptBlock {
[net.servicepointmanager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12
Install-module pswindowsupdate -force -AllowClobber
Get-WUInstall -AcceptAll

Get-PSSession | Remove-PSSession 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

How to install Windows Updates Remotely prior to  Windows Server 2016/Windows 10

As we have already create the script to install the PSWindowsUpdate module the only thing that must change is the line 

Get-WindowsUpdates with the Get-WUInstall.

How to use the Get-WUInstall depends from you.

  • if we want to install all the Updates or not.
  • If you want to restart the Server/Workstation or not

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Enable-WSManCredSSP -Role Client -DelegateComputer computernames -Force
$session1,$session2=New-PSSession -ComputerName computernames
Invoke-Command -Session $session1,$session2  -ScriptBlock { 
Enable-WSManCredSSP -Role Server -Force 
}
Get-PSSession | Remove-PSSession 

$session=New-PSSession -ComputerName computernames -Authentication Credssp -Credential "credential of admin account"
Invoke-Command -Session $session  -ScriptBlock { 
Import-Module  "share path of the PSWindowsUpdate.psd1"
Get-WUInstall -AcceptAll
Disable-WSManCredSSP -Role Server

Disable-WSManCredSSP -Role Client
Get-PSSession | Remove-PSSession 

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

How to Check Windows Update History

Sometimes we need to check the Windows update History and the Status from each Windows Updates. You can write down the following command

Get-WUHistory

  • You can filter the results based on Date or how many install Windows update you would like to see.
  • You can retrieve only the last 10 Windows updates. 

Get-WUHistory -Last 10

 

  • Or you can retrieve all the Windows Updates from the last day

Get-WUHistory -MaxDate (Get-Date).AddDays(-1)

 

How to check when the Windows updates installed last time

If you would like to see only the Windows updates that they are installed last time type the following command

Get-WULastResults

 

 

How to schedule a task for the Windows Updates

The PSWindowsUpdate module include the Invoke-WUJob to create a schedule task for the Windows Update in the remote computers. However the cmdlet support only to create a schedule task that will run once.

The scope is to automate the Windows Updates instead to run manual the script every month.

So I mixed up a script with a few manual configuration to create a Schedule task that will run the Windows Update each month.

Let's see it in practice.

The scenario is the following:

We will create a schedule task with the cmdlet Invoke-WUJob locally. We will give the name WindowsUpdates. Then we will change a few settings from the schedule task WindowsUpdates to run each month and we will export the task in xml file. After that we will run a script to create a schedule task in remote computers from the xml file.  

#Step 1 - Create the schedule task with the Invoke-WUJob

  • From the endpoint that you have already installed the PSWindowsUpdate module run the following command to create the schedule task locally. We don't care about the TriggerDate because we will change it.

        Invoke-WUJob -Script {Get-WindowsUpdate -Install -AcceptAll}  -TriggerDate (Get-Date -Hour 22 -Minute 55 -Second 0) -Confirm:$false -Verbose

Use the Invoke-WUJob from PSWindowsUpdate

 

#Step 2 - Change a few settings in the schedule task

  • Open the Task Scheduler and find the Task WindowsUpdates. 
  • Edit the Task and go to the tab Trigger
  • Edit the Trigger and on the Settings from the OneTime change it to Monthly.
  • Click on the Months and select all the Months.
  • Click the dropdown of the On and select Second. In the next dropdown select Friday.
  • Microsoft publishing the Windows Updates second Tuesday of each Month. We scheduled to run the Windows Updates the second Friday of each month.
  • Uncheck the Expire as well. Click OK.

 

  • Click the Tab Settings. Uncheck the if the task is not scheduled to run again delete it after: Click OK

 

#Step 3 Export the schedule task in xml file

Now that we have configured the schedule task to run on second Friday each month we can go ahead to export it.

  • Right click on the the Task and select Export. Select the location that you would like to save it.
  • Use a share location that can have access. The xml file will be used the time that you will create the new task to the remote pcs or Servers.

#Step 4 Create the schedule task from the xml file to the remote computers

Before proceed with this task we need to fullfill the following prerequisites

  1. Enable WsMan on the Remote PCs to allow remote connections from  PowerShell.
  2. Enable the TLS1.2 security protocol in PowerShell to be able download and install the Nuget Package Provider that requested before install the Pswindowsupdate. You can run the following command ​​​when you will complete the first step. We will not close the sessions because it will be used for the step 3.

        $session=New-PSSession -ComputerNames <yourcomputernames>  -Credential "credential of admin account"
        Invoke-Command -Session $session  -ScriptBlock {[net.servicepointmanager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12}

   3. Install the PSWindowsUpdate module to the remote pcs and close the sessions.

       Invoke-Command -Session $session  -ScriptBlock {Install-module pswindowsupdate -force -AllowClobber}
       Get-PSSession | Remove-PSSession 

  4. Create a new task from the xml file to the remote pc's or Servers.

      Invoke-Command -ComputerName dcsrv1 -ScriptBlock {Register-ScheduledTask -xml (Get-Content "C:\Temp\Windowsupdates.xml"| out-string)   -TaskName WindowsUpdates}

 

That's it!!

Now each PC or Server that you ran the script have been created a Task Scheduler that will run every 2nd Friday of the month to download the Windows Updates.

 

How to find out the Failed Windows Updates

As all we know sometimes Windows Updates failed to install. If we are responsible for the Patching we should know which Windows Updates have been failed.

You can use the following command to determine only the Windows updates that failed. 

Get-WUHistory | Where {$_.Result -eq 'Failed'}

 

Flexible and quick solution for those that need to Centralize Windows Updates without the WSUS

You can find another one great article for the PSWindowsUpdate module and how can use it from Harm Veenstra

To be honest the installation prior to Windows Server 2016/Windows 10 it's not so easy but you will spend time  only once until customize your script. After that  you can use it as a schedule Task.

Imagine how much time you can save.

You will not have the options and possibilities that give you the  WSUS but it's a simple way to keep all the Windows PC and Servers up to date without need to spend lot of time.

The most time that you will spend will be the first time until manage all the Servers and Workstations to install the available Windows Updates.