James O'Neill's blog

Windows Platform, Virtualization and PowerShell with a little Photography for good measure.

Managing Windows Update with PowerShell

Managing Windows Update with PowerShell

  • Comments 9
  • Likes

I mentioned some of the server management and config tools I’ve been creating with Server 2008 R2 core in mind, and I’m going to put the major bits here. I’ll post the whole script at the end of the set of posts but for now here is the code to look after Windows update

First I created two hash tables to map the numbers used in the functions to some meaningful text

$AutoUpdateNotificationLevels= @{0="Not configured"; 1="Disabled" ; 2="Notify before download"; 
3="Notify before installation"; 4="Scheduled installation"}
$AutoUpdateDays=@{0="Every Day"; 1="Every Sunday"; 2="Every Monday"; 3="Every Tuesday"; 4="Every Wednesday";
5="Every Thursday"; 6="Every Friday"; 7="EverySaturday"}

Next, there is a COM object for everything relating to auto-update. It has a settings property which contains the notification level and update days, the hour at which updates are fetched and how recommended updates are processed.  Setting the properties is pretty easy, and there is is a save method to commit them  - I’ve been lazy here and haven’t got a hash table mapping names to numbers for the notification level so or multiple switches so the user would need to know that notification levels in the hash table (or enter  $AutoUpdateNotificationLevels at the prompt to see what is in the table) – I might fix that for the final script.

 Function Set-WindowsUpdateConfig

{Param ($NotificationLevel , $Day, $hour, $IncludeRecommended)
$AUSettings = (New-Object -com "Microsoft.Update.AutoUpdate").Settings
if ($NotificationLevel)  {$AUSettings.NotificationLevel        =$NotificationLevel}
if ($Day)                {$AUSettings.ScheduledInstallationDay =$Day}
if ($hour)               {$AUSettings.ScheduledInstallationTime=$hour}
if ($IncludeRecommended) {$AUSettings.IncludeRecommendedUpdates=$IncludeRecommended}
$AUSettings.Save
}

To show what the settings are, I decode them and return a custom object with the decoded properties.

Function Get-WindowsUpdateConfig

{$AUSettings = (New-Object -com "Microsoft.Update.AutoUpdate").Settings
$AUObj = New-Object -TypeName System.Object
 Add-Member -inputObject $AuObj -MemberType NoteProperty -Name "NotificationLevel"   `
    -Value $AutoUpdateNotificationLevels[$AUSettings.NotificationLevel]
Add-Member -inputObject $AuObj -MemberType NoteProperty -Name "UpdateDays"      `
       -Value $AutoUpdateDays[$AUSettings.ScheduledInstallationDay]
Add-Member -inputObject $AuObj -MemberType NoteProperty -Name "UpdateHour"        `
   -Value $AUSettings.ScheduledInstallationTime Add-Member -inputObject $AuObj -MemberType NoteProperty -Name "Recommended updates" `
-Value $(IF ($AUSettings.IncludeRecommendedUpdates) {"Included."}  else {"Excluded."}) $AuObj
} 

Checking on MSDN I found there is another object used in a script WUA_SearchDownloadInstall , which does what it says – it searches Windows update for updates, downloads them and installs them I added the logic to my function to over-ride the selection criteria, and auto-Restart if a restart is needed. Since it is sometimes useful to patch Virtual Machines, then shut them down, then Patch the host and then reboot it and bring the VMs back again , I’ve also put in a shutdown after Update switch.

The logic is simple enough, create a Session object which has CreateSearcher, CreateDownloader and CreateInstaller Methods. Then create a searcher and use it to get updates matching the default or specified criteria. If there are any updates, create a downloader object, hand it the list of updates found by the searcher and start a download. If the download completes successfully, filter out the successfully downloaded items, and pass those into a newly created installer object. Run the installation process and afterwards output a table showing the state of the updates. Finally reboot if needed.

Function Add-WindowsUpdate

{param ($Criteria="IsInstalled=0 and Type='Software'" , [switch]$AutoRestart, [Switch]$ShutdownAfterUpdate)
$resultcode= @{0="Not Started"; 1="In Progress"; 2="Succeeded"; 3="Succeeded With Errors"; 4="Failed" ; 5="Aborted" }
$updateSession = new-object -com "Microsoft.Update.Session"
write-progress -Activity "Updating" -Status "Checking available updates" 
$updates=$updateSession.CreateupdateSearcher().Search($criteria).Updates
if ($Updates.Count -eq 0)  { "There are no applicable updates."}  
else {
       $downloader = $updateSession.CreateUpdateDownloader()
       $downloader.Updates = $Updates 
        write-progress -Activity 'Updating' -Status "Downloading $($downloader.Updates.count) updates" 
       $Result= $downloader.Download() 
       if (($Result.Hresult -eq 0) –and (($result.resultCode –eq 2) -or ($result.resultCode –eq 3)) ) {

       $updatesToInstall = New-object -com "Microsoft.Update.UpdateColl"
       $Updates | where {$_.isdownloaded} | foreach-Object {$updatesToInstall.Add($_) | out-null }
       $installer = $updateSession.CreateUpdateInstaller()
       $installer.Updates = $updatesToInstall
       write-progress -Activity 'Updating' -Status "Installing $($Installer.Updates.count) updates'
        $installationResult = $installer.Install()
        $Global:counter=-1
        $installer.updates | Format-Table -autosize -property Title,EulaAccepted,@{label='Result';
                               expression={$ResultCode[$installationResult.GetUpdateResult($Global:Counter++).resultCode ] }}
       if ($autoRestart -and $installationResult.rebootRequired) { shutdown.exe /t 0 /r }
       if ($ShutdownAfterUpdate) {shutdown.exe /t 0 /s }
}
} }

So now I can run
Add-WindowsUpdate –Auto to download updates and reboot if needed,
Set-WindowsUpdateConfig –n 4 –i to schedule updates (Including the merely recommended)  and
Get-WindowsUpdateConfig

So next up it’s Get-RemoteDesktopConfig and Set-RemoteDesktopConfig.

Comments
  • PingBack from http://www.clickandsolve.com/?p=2577

  • haven't try it.

    But what is "$Result.Hresult 0 = OK"?

    Thanks

  • An error ! Somehow I didn't pick up that  I was using = instead of -eq !

  • I have been trying for five days to install SQL Server Express 2008.  After uninstalling for the 2nd time, I'm now trying it again.  I reach a point where it says I need Windows Powershell.  OK, so I go to the download page and it says I have to run Windows Validation.  I did this, come back to the Powershell page and guess what .. nowhere on the page is a button that says download that actually downloads.  You go around in circles for about another hour or two and frankly I so cooked that I want to just send the computer back to Dell and take up golf .. This system defines "arcane," "useless" and "frustrating."

    Richard Earp (earpr@bellsouth.net)

  • Richard , if you are server 2008 go to Server manager, features, and click install it.

    For anything else go to www.microsoft.com  and type Download PowerShell in the search oox, follow the top link and click your OS. I tried a random selection and they all worked.

  • Why are you checking if the resultCode is = 2 twice ?

    if (($Result.Hresult 0 -eq OK) –and (($result.resultCode –eq 2) or ($result.resultCode –eq 2)) )

  • Alright,

    I put the IF in when I posted it here and just have a note in the original code. The original had a comment hresult 0  = OK , (meaning to me if hresult is 0 that means "OK") and seem to have moved it round wrongly.

    I meant to hook the Result.ResultCode to the hash table so if it was "Succeed",  or "Downloaded some succeeded and some errors" then it would continue,it should have be 2 and 3 in that line and I put 2 in twice. DOH !

  • Джеймс О’Нил (James O’Neil) написал, как управлять Windows Update с помощью Windows PowerShell Вот краткий

  • Джеймс О’Нил (James O’Neil) написал, как управлять Windows Update с помощью Windows PowerShell Вот краткий

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment