Apr 072011
 

If you have a WSUS server and deploy new or re-image computers on a regular basis you know that waiting for Windows to find the latest updates can be slow. This PowerShell script will help speed up the process by using with the Microsoft.Update.Session COM object to force the download an install of the latest approved updates.

This powershell script is adapted from the VBScript (WUA_SearchDownloadInstall.vbs) Microsoft released. However, unlike the Microsoft equivalent it eliminates the need for user input intervention by providing the ability to pass command line arguments.

#      Script: WSUS.ps1
#      Author: Gregory Strike
#         URL: http://www.gregorystrike.com/2011/04/07/force-windows-automatic-updates-with-powershell/
#        Date: 02-19-2010
# Information: This script was adapated from the WUA_SearchDownloadInstall.vbs VBScript from Microsoft.  It uses the
#              Microsoft.Update.Session COM object to query a WSUS server, find applicable updates, and install them.
#
#              WSUS.ps1 is a little less verbose about what it is doing when compared to the orginal VBScript.  The
#              lines exist in the code below to show the same information as the original but are just commented out.
#
#              WSUS.ps1 can automatically install applicable updates by passing a Y to the script.  The default
#              behavior is to ask whether or not to install the new updates.
#
#              Syntax:  .\WSUS.ps1 [Install] [Reboot]
#                       Where [Install] is optional and can be "Y", "Yes", "No" or "N"
#                       Whether or not to install the updates automatically.  If Null, the user will be prompted.
#
#                       Where [Reboot] is optional and can be "Y", "Yes", "No" or "N",  This 
#                       If updates require a reboot, whether or not to reboot automatically.  If Null, the user will
#                       be prompted.
#
#     License: This script is free to use given the following restrictions are followed.
#              1. When used the Author and URL above must remain in place, unaltered.
#              2. Do not publish the contents of this script anywhere. Instead a link 
#                 must be provided back to the URL listed above.
#
#      Update: 5/30/2012 - Fixed the "Privilege not held" error that caused script to fail when requesting a reboot.
 
$UpdateSession = New-Object -Com Microsoft.Update.Session
$UpdateSearcher = $UpdateSession.CreateUpdateSearcher()
 
Write-Host("Searching for applicable updates...") -Fore Green
 
$SearchResult = $UpdateSearcher.Search("IsInstalled=0 and Type='Software'")
 
Write-Host("")
Write-Host("List of applicable items on the machine:") -Fore Green
For ($X = 0; $X -lt $SearchResult.Updates.Count; $X++){
    $Update = $SearchResult.Updates.Item($X)
    Write-Host( ($X + 1).ToString() + "> " + $Update.Title)
}
 
If ($SearchResult.Updates.Count -eq 0) {
    Write-Host("There are no applicable updates.")
    Exit
}
 
#Write-Host("")
#Write-Host("Creating collection of updates to download:") -Fore Green
 
$UpdatesToDownload = New-Object -Com Microsoft.Update.UpdateColl
 
For ($X = 0; $X -lt $SearchResult.Updates.Count; $X++){
    $Update = $SearchResult.Updates.Item($X)
    #Write-Host( ($X + 1).ToString() + "> Adding: " + $Update.Title)
    $Null = $UpdatesToDownload.Add($Update)
}
 
Write-Host("")
Write-Host("Downloading Updates...")  -Fore Green
 
$Downloader = $UpdateSession.CreateUpdateDownloader()
$Downloader.Updates = $UpdatesToDownload
$Null = $Downloader.Download()
 
#Write-Host("")
#Write-Host("List of Downloaded Updates...") -Fore Green
 
$UpdatesToInstall = New-Object -Com Microsoft.Update.UpdateColl
 
For ($X = 0; $X -lt $SearchResult.Updates.Count; $X++){
    $Update = $SearchResult.Updates.Item($X)
    If ($Update.IsDownloaded) {
        #Write-Host( ($X + 1).ToString() + "> " + $Update.Title)
        $Null = $UpdatesToInstall.Add($Update)        
    }
}
 
$Install = [System.String]$Args[0]
$Reboot  = [System.String]$Args[1]
 
If (!$Install){
    $Install = Read-Host("Would you like to install these updates now? (Y/N)")
}
 
If ($Install.ToUpper() -eq "Y" -or $Install.ToUpper() -eq "YES"){
    Write-Host("")
    Write-Host("Installing Updates...") -Fore Green
 
    $Installer = $UpdateSession.CreateUpdateInstaller()
    $Installer.Updates = $UpdatesToInstall
 
    $InstallationResult = $Installer.Install()
 
    Write-Host("")
    Write-Host("List of Updates Installed with Results:") -Fore Green
 
    For ($X = 0; $X -lt $UpdatesToInstall.Count; $X++){
        Write-Host($UpdatesToInstall.Item($X).Title + ": " + $InstallationResult.GetUpdateResult($X).ResultCode)
    }
 
    Write-Host("")
    Write-Host("Installation Result: " + $InstallationResult.ResultCode)
    Write-Host("    Reboot Required: " + $InstallationResult.RebootRequired)
 
    If ($InstallationResult.RebootRequired -eq $True){
        If (!$Reboot){
            $Reboot = Read-Host("Would you like to reboot now? (Y/N)")
        }
 
        If ($Reboot.ToUpper() -eq "Y" -or $Reboot.ToUpper() -eq "YES"){
            Write-Host("")
            Write-Host("Rebooting...") -Fore Green
            $WMIReboot = Get-WMIObject -Class Win32_OperatingSystem
            $WMIReboot.PSBase.Scope.Options.EnablePrivileges = $True
            $WMIReboot.Reboot()
        }
    }
}
  • P Ziegler

    Hi there.
    Thanks for the good work.
    I want to inform you that there is a typo in the line:
    ” If ($InstallationResult.RebootRequire -eq $True){”
    near the end of the script.

    Please correct it as follows: ” If ($InstallationResult.RebootRequired -eq $True){”
    Peter

    • http://www.gregorystrike.com/ Gregory Strike

      Thanks Peter. I’ll update the post!

  • Pingback: Script em Powershell para aplicar updates em sistemas Windows. « Infragreen()

  • http://twitter.com/eotwshirt EOTWshirt

    This is a really clean script, but I can’t get it to restart automatically.

    When I run:

    ./wsus.ps1 yes yes

    Everything installs automatically, however I receive the prompt to “Restart Now” or “Postpone”

    • http://www.gregorystrike.com/ Gregory Strike

      EOTWShirt, I’ve updated the script and it may fix your issue.  Let me know!

      • http://www.facebook.com/people/Greg-Sher/100000775786475 Greg Sher

        Works great now. Thanks!

  • Wilfredo Maldonado

    Yeah, just so everyone knows the “truth” but this script will not work in its entirety, so the updates will be found, will download, will install but it will not reboot. You will see some gibberish but basically it is will say “Privilege Not Held” because you cannot initiate a reboot of the machine where you run the script, so others have run the script on other machines calling the machine in question but if you use something like AdminArsenal then you know the script is copied over and run.
    I won’t try to solve the problem above and will leave that to Gregory to troubleshoot his code because it is flying all over the internet but does not work 100% meanwhile I just upgraded my VMs to PowerShell 2.0 and then I can just swap out his line for REBOOT with:
    Restart-Computer

    Problem solved for me, but I guess others might still be running PowerShell 1.0 so upgrade dammit… :)

    • http://www.gregorystrike.com/ Gregory Strike

      Wilfredo,  Thanks for bringing this issue to my attention.  I’ve posted an update to the script above and I believe it will fix the issue.  I’ve replace the single Reboot line with:

      $WMIReboot = Get-WMIObject -Class Win32_OperatingSystem
      $WMIReboot.PSBase.Scope.Options.EnablePrivileges = $True
      $WMIReboot.Reboot()

      However, I’m not 100% certain that will work on PowerShell 1.0.  I believe it will.  I would like to hear if it does not.  There’s another method I could do that would launch the shutdown.exe task as a remote process, so it wouldn’t be within PowerShell, and should work, I just thought the above fix was cleaner.

  • Pingback: Microsoft and SAP NetWeaver - step by step up to the cloud - Part III : some thoughts about automated Windows patching - Running SAP Applications on SQL Server - Site Home - MSDN Blogs()

  • Kenneth Pearce

    Can I execute this from my desktop and have it work against a remote machine?

  • LUCKY ADMIN

    EXCELLENT SCRIPT!!! SAVED HOURS SIR!!!

  • Jocke

    i am having some issues with this script, i want to run it remotly on a number of computers, however when i tried it against my colleagues computer i got this:
    C:skripts> Invoke-Command -ComputerName mawe-764 -FilePath .wsus.ps1 -ArgumentList y,ySearching for applicable updates…
    List of applicable items on the machine:1> Security Update for Windows 7 for x64-based Systems (KB2698365)2> ….
    Downloading Updates…Exception calling “CreateUpdateDownloader” with “0” argument(s): “Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))”

    useing a domain admin account that are local administrator on his computer, he also enabled psremoting and started the winrm service

    any ideas?

  • jocke

    also, it will list my applicable updates but while starting to download them, the script stops…

    does this have anything to do with wsus policy settings?

    /J

  • Andre

    First of all, great script, thank you for sharing it with us!!
    Is there an easy way to write the installed patches or the Status of what the script did into a text file? Could be helpful if it is running as scheduled Task to check what was installed or if there was any error during the run…

  • Ghe

    Great !
    I customize his execution for managing update on hyper-v cluster nodes, works very well !

  • Troy Frank

    anyone else have jocke’s problem? I did, and haven’t been able to find a solution so far.

  • Colin Westwater

    I am having the exact same issue as Jocke. Can anyone help? Many thanks to Gregory for such a useful script!