30 August 2019

SCCM/MDT Windows Updates Installer

One of the issues I have had when moving the build process from MDT to SCCM has been windows updates. Windows updates are not available in the SCCM build if it does not already deploy the updates to machines. Except for servers, the user machines are configured to install updates pushed down by Microsoft as shown below. Before asking about managing the updates, I do have tools put in place to be able to quickly stop updates from installing and remove updates if issues come up.


To get updates installed in the SCCM build process, I started by downloading and installing the PSWindowsUpdate PowerShell Module written by Michal Gajda. This module is fantastic for managing updates.

Next, I wrote the following PowerShell script that does the following things. The first thing that needs to be done is to make sure the PowerShellGet module is present before running the script. The script will check if the latest version of PSWindowsUpdate is installed. If not, it installs it. This will also install it if it is not already present. Next, it will query Microsoft for a list of missing updates. If there are no updates, then the script exits with an error code 0. If there are updates, it will proceed to install them. There was one problem I ran into when writing this script. It did not have sufficient privileges to install the updates. It needed to be run-as-administrator. The workaround for this is to add the account the script is run under to the administrators group on the local machine, which is what the script does. After adding to the administrators group, it installs the updates, while suppressing a reboot. After this is finished, it removes the user from the administrators group. There are four conditions it will then check for to see if a reboot is pending. If it is pending, then the script will initiate a reboot via SCCM if the -SCCM switch is in the parameters field, and it instructs SCCM to rerun the same task. If there is not a pending reboot, then the script checks for additional updates and installs them.

To implement it in SCCM, I used a Run PowerShell Script task sequence. The entire script below was pasted into the Edit Script field of the Enter a PowerShell Script:. I did also use the -SCCM parameter. he Run this step as the following account was also selected that uses the build account.



You can download the script from my GitHub site.


 <#  
      .SYNOPSIS  
           Install Windows Updates  
        
      .DESCRIPTION  
           This script uses the PSWindowsUpdate module to install the latest windows updates. It also makes sure the latest version of the module is installed. It is designed to run in SCCM, MDT, and in a deployment.  
        
      .PARAMETER SCCM  
           This specifies for the script to use the Microsoft.SMS.TSEnvironment comobject for managing the reboot and re-execution of the Windows Update Task  
        
      .NOTES  
           ===========================================================================  
           Created with:     SAPIEN Technologies, Inc., PowerShell Studio 2017 v5.4.142  
           Created on:       8/29/2019 7:22 AM  
           Created by:       Mick Pletcher  
           Filename:         InstallWindowsUpdates.ps1  
           ===========================================================================  
 #>  
 [CmdletBinding()]  
 param  
 (  
      [switch]$SCCM  
 )  
 function Enable-Reboot {  
 <#  
      .SYNOPSIS  
           Reboot Machine  
        
      .DESCRIPTION  
           This function will reboot the machine. If the SCCM switch is defined, it will use the task sequence environmental variables to reboot the machine and restart the task sequence.   
        
      .NOTES  
           Additional information about the function.  
 #>  
        
      [CmdletBinding()]  
      param ()  
        
      If ($SCCM.IsPresent) {  
           $TaskSequence = New-Object -ComObject Microsoft.SMS.TSEnvironment  
           #Rerun this task when the reboot finishes   
           $TaskSequence.Value('SMSTSRetryRequested') = $true  
           #Reboot the machine when this command line task sequence finishes   
           $TaskSequence.Value('SMSTSRebootRequested') = $true  
      } else {  
           Restart-Computer -Force  
      }  
 }  
   
 Import-Module PowerShellGet  
 Import-Module -Name PSWindowsUpdate -ErrorAction SilentlyContinue  
 #Get the version of PSWindowsUpdate that is currently installed  
 $InstalledVersion = (Get-InstalledModule -Name PSWindowsUpdate).Version.ToString()  
 #Get the current version of PSWindowsUpdate that is available in the PSGallery  
 $PSGalleryVersion = (Find-Module -Name PSWindowsUpdate).Version.ToString()  
 #Uninstall and install PSWindowsUpdate module if the installed version does not match the version in PSGallery  
 If ($InstalledVersion -ne $PSGalleryVersion) {  
      Install-Module -Name PSWindowsUpdate -Force  
 }  
 #Get the list of available windows updates  
 $Updates = Get-WindowsUpdate  
 If ($Updates -ne $null) {  
      $NewUpdates = $true  
      Do {  
           #Add $AdminUser to Administrators group  
           Add-LocalGroupMember -Group Administrators -Member ($env:USERDOMAIN + '\' + $env:USERNAME)  
           #Install windows updates  
           Install-WindowsUpdate -AcceptAll -IgnoreReboot -Confirm:$false  
           #Remove $AdminUser from the Administrators group  
           Remove-LocalGroupMember -Group Administrators -Member ($env:USERDOMAIN + '\' + $env:USERNAME)  
           #Component Based Reboot   
           If ((Get-ChildItem "REGISTRY::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending" -ErrorAction SilentlyContinue) -ne $null) {  
                Enable-Reboot  
                $NewUpdates = $false  
           #Windows Update Reboot   
           } elseif ((Get-Item -Path "REGISTRY::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" -ErrorAction SilentlyContinue) -ne $null) {  
                Enable-Reboot  
                $NewUpdates = $false  
           #Pending Files Rename Reboot   
           } elseif ((Get-ItemProperty -Path "REGISTRY::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager" -Name PendingFileRenameOperations -ErrorAction SilentlyContinue) -ne $null) {  
                Enable-Reboot  
                $NewUpdates = $false  
           #Pending SCCM Reboot   
           } elseif ((([wmiclass]"\\.\root\ccm\clientsdk:CCM_ClientUtilities").DetermineIfRebootPending().RebootPending) -eq $true) {  
                Enable-Reboot  
                $NewUpdates = $false  
           }  
           #If no pending reboot, then check for new updates  
           If ($NewUpdates -eq $true) {  
                #Check for new windows updates  
                $Updates = Get-WindowsUpdate  
                #No reboot was required from last installed updates, so check if new updates are available and end loop if not  
                If ($Updates -eq $null) {  
                     $NewUpdates -eq $false  
                }  
           }  
      } While ($NewUpdates -eq $true)  
 } else {  
      Exit 0  
 }  
   

1 comments:

  1. Hello,

    Where did you put this step? I can't get this work on my SCCM task sequence. When i copied the powershell script to the task sequence and when i deploy it nothing happens. It just runs the step without downloading anything. The task sequence doesn't error out either. Any help will be appreciated.

    ReplyDelete