{"id":54213,"date":"2009-03-11T21:21:00","date_gmt":"2009-03-11T21:21:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2009\/03\/11\/hey-scripting-guy-how-can-i-search-for-download-and-install-an-update\/"},"modified":"2009-03-11T21:21:00","modified_gmt":"2009-03-11T21:21:00","slug":"hey-scripting-guy-how-can-i-search-for-download-and-install-an-update","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-search-for-download-and-install-an-update\/","title":{"rendered":"Hey, Scripting Guy! How Can I Search For, Download, and Install an Update?"},"content":{"rendered":"<p><H2><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\"> <\/H2>\n<P>Hey, Scripting Guy! Reporting on whether a Windows Update is installed or not is pretty cool. However, what happens when I determine the update has not been applied? Am I supposed to call the user and talk them through connecting to the Microsoft Update site and choosing the appropriate update? That may work for one or two users, but it does not scale very well. Surely you have a better plan than that? I mean, you are after all the Microsoft Scripting Guy, not the Microsoft Talks the User Through the GUI Guy. You got a script for me?<BR><BR>&#8211; NB<\/P><IMG border=\"0\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" height=\"5\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\"> \n<P>Hi NB,<\/P>\n<P>Well, we are snowed in down here in Charlotte today. It\u2019s a <A href=\"http:\/\/dictionary.reference.com\/browse\/snow+day\" target=\"_blank\">snow day<\/A>! Woo Hoo! Hey, wait a minute, I work from home, so not much of a snow day after all. Oh well. It looks pretty from my office windows, and the neighbors are in the street with their various snow implements. Looks cold; luckily I am sipping a cup of Constant Comment tea and listening to the <A href=\"http:\/\/en.wikipedia.org\/wiki\/The_Kentucky_Headhunters\" target=\"_blank\">Kentucky Headhunters<\/A> on my <A href=\"http:\/\/en.wikipedia.org\/wiki\/Zune\" target=\"_blank\">Zune<\/A>. So you want to be able to search for an update, download the update, and install the update? No problem.<\/P>\n<TABLE id=\"EED\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\">This week we will be looking at using the Windows Update API to work with Windows Update. The Windows Update API is documented <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa387099.aspx\" target=\"_blank\">on MSDN<\/A>. There is also a good collection of VBScripts that use the Windows Update API in the <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/scripts\/default.mspx?mfr=true\" target=\"_blank\">Script Center Script Repository<\/A>. For information about manually configuring Windows Update on workstations, refer to <A href=\"http:\/\/www.microsoft.com\/windows\/downloads\/windowsupdate\/learn\/windowsvista.mspx\" target=\"_blank\">this page<\/A>. These scripts use Windows PowerShell. <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/hubs\/msh.mspx\" target=\"_blank\">The Windows PowerShell getting started page<\/A> has basic information for learning about Windows PowerShell and about downloading Windows PowerShell.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>Today&#8217;s script is called <B>InstallSoftwareUpdate.ps1<\/B> and is seen here (a VBScript version of today&#8217;s script can be seen in the <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/scripts\/sus\/client\/suclvb03.mspx\" target=\"_blank\">Script Center Script Repository<\/A>):<\/P><PRE class=\"codeSample\"><PRE class=\"codeSample\">$UpdateCollection = New-Object -ComObject Microsoft.Update.UpdateColl\n$Searcher = New-Object -ComObject Microsoft.Update.Searcher\n$Session = New-Object -ComObject Microsoft.Update.Session<\/p>\n<p>$updateID = &#8220;f1b1a591-bb75-4b1c-9fbd-03eedb00cc9d&#8221;\n$Result = $Searcher.Search(&#8220;UpdateID=&#8217;$updateID'&#8221;)\n$Updates = $Result.updates\n$UpdateCollection.Add($Updates.Item(0)) | out-null<\/p>\n<p>$Downloader = $Session.CreateUpdateDownloader()\n$Downloader.Updates = $UpdateCollection\n$Downloader.Download()<\/p>\n<p>$Installer = New-Object -ComObject Microsoft.Update.Installer\n$Installer.Updates = $UpdateCollection\n$Installer.Install()\n<\/PRE><\/PRE>\n<P>The first thing we need to do is to create an instance of the <B>Microsoft.Update.UpdateColl<\/B> object. This object is known as the <B>IUpdateCollection<\/B> interface and it is documented <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa386107(VS.85).aspx\" target=\"_blank\">on MSDN<\/A>. To create the <B>UpdateColl<\/B> object, we use the <B>New-Object<\/B> cmdlet and specify the <B>\u2013ComObject<\/B> parameter and use the <B>Microsoft.Update.UpdateColl<\/B> program ID. The pattern for creating these objects is seen here:<\/P><PRE class=\"codeSample\">$VariableToHoldObject = New-Object \u2013ComObject ProgramIDOFTheComObject<\/PRE>\n<P>We store the returned <B>UpdateColl<\/B> object in the <B>$UpdateCollection<\/B> variable as shown here:<\/P><PRE class=\"codeSample\">$UpdateCollection = New-Object -ComObject Microsoft.Update.UpdateColl<\/PRE>\n<P>Next we need to create the <B>Searcher<\/B> object. The <B>Microsoft.Update.Searcher<\/B> object (also known as the <B>IUpdateSearcher<\/B> interface) is documented <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa386515(VS.85).aspx\" target=\"_blank\">on MSDN<\/A>. To create the <B>Searcher<\/B> object, we use the <B>New-Object<\/B> cmdlet with the <B>\u2013ComObject<\/B> parameter and supply the Program ID of <B>Microsoft.Update.Searcher<\/B>. We store the returned <B>Searcher<\/B> object in the <B>$Searcher<\/B> variable. This is seen here:<\/P><PRE class=\"codeSample\">$Searcher = New-Object -ComObject Microsoft.Update.Searcher<\/PRE>\n<P>The next object we need to create is the <B>Session<\/B> object. This object, like the other two objects, begins with <B>Microsoft.Update<\/B>. It also is created with the <B>New-Object<\/B> cmdlet. Also known as the <B>IUpdateSession<\/B> interface, it is documented <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa386854(VS.85).aspx\" target=\"_blank\">on MSDN<\/A>. The code that creates the <B>Session<\/B> object is seen here:<\/P><PRE class=\"codeSample\">$Session = New-Object -ComObject Microsoft.Update.Session<\/PRE>\n<P>To install a software update, we need to first search for the update, add the retrieved update to the update collection, download the update, and finally install the update. If we want to install a specific update, we can use the <B>updateID<\/B> property from the <B>Update Identity<\/B> object. To easily retrieve updateIDs for software updates that are not yet installed, we can use the <B>ListSoftwareUpdatesNotInstalled.ps1<\/B> script (this script is a revision of the <B>ListSoftwareUpdates.ps1<\/B> script we looked at <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/mar09\/hey0310.mspx\" target=\"_blank\">yesterday<\/A>):<\/P><PRE class=\"codeSample\">$Searcher = New-Object -ComObject Microsoft.Update.Searcher\n$results = $searcher.search(&#8220;Type=&#8217;software&#8217; AND IsInstalled = 0&#8221;)\n$Results.Updates | \nForEach-Object { $_.Identity.UpdateID ; &#8220;`t&#8221; + $_.Title }<\/PRE>\n<P>We have added the <B>ForEach-Object<\/B> cmdlet to allow us to return the <B>updateID<\/B> property from the <B>Update Identity<\/B> object. We then tab over by using the <B>&#8220;`t&#8221;<\/B> and print out the title of the update as well by concatenating it via the plus sign <B>(+)<\/B>. The results are seen here:<\/P><IMG border=\"0\" alt=\"Image of the updateID and title of each update\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/march\/hey0311\/hsg-3-11-9-1.jpg\" width=\"668\" height=\"199\"> \n<P>&nbsp;<\/P>\n<P>After we have found the update we wish to install, we copy the updateID and assign it to the <B>$UpdateID<\/B> variable. We then use this variable when we call the <B>Search <\/B>method from the <B>Searcher<\/B> object. The query we use for the <B>Searcher<\/B> object is <B>UpdateID =<\/B> the value stored in the <B>$updateID<\/B> variable. The <B>Searcher<\/B> syntax was discussed in <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/mar09\/hey0310.mspx\" target=\"_blank\">yesterday\u2019s \u201cHey, Scripting Guy!\u201d article<\/A>.<\/P>\n<P>After the update has been found, it is added to the <B>UpdateCollection<\/B> by using the <B>Add<\/B> method. The return code from adding the update to the collection is discarded by piping it to the <B>Out-Null<\/B> cmdlet. The <B>updateID<\/B> f1b1a591-bb75-4b1c-9fbd-03eedb00cc9d is the Windows Search 4.0 for Windows XP (KB940157) update. This section of the code is seen here:<\/P><PRE class=\"codeSample\">$updateID = &#8220;f1b1a591-bb75-4b1c-9fbd-03eedb00cc9d&#8221;\n$Result = $Searcher.Search(&#8220;UpdateID=&#8217;$updateID'&#8221;)\n$Updates = $Result.updates\n$UpdateCollection.Add($Updates.Item(0)) | out-null\n<\/PRE>\n<P>We now need to download the updates. To do this, we use the <B>CreateUpdateDownloader<\/B> method from the <B>Session<\/B> object. The resulting download object is stored in the <B>$Downloader<\/B> variable. The updates from the <B>UpdateCollection<\/B> are assigned to the <B>Updates<\/B> property of the <B>Downloader<\/B>, and the <B>Download<\/B> method is called. This section of the script is seen here:<\/P><PRE class=\"codeSample\">$Downloader = $Session.CreateUpdateDownloader()\n$Downloader.Updates = $UpdateCollection\n$Downloader.Download()\n<\/PRE>\n<P>Now it is time to install the update. To do this, we need to first create an instance of the <B>Installer<\/B> object. The <B>Installer<\/B> object (also known as the <B>IUpdateInstaller<\/B> interface) is documented <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa386491(VS.85).aspx\" target=\"_blank\">on MSDN<\/A>. After the Installer object is created, we use the updates stored in the <B>$updateCollection<\/B> variable and assign it to the <B>Updates<\/B> property. We then call the <B>Install<\/B> method as seen here:<\/P><PRE class=\"codeSample\">$Installer = New-Object -ComObject Microsoft.Update.Installer\n$Installer.Updates = $UpdateCollection\n$Installer.Install()\n<\/PRE>\n<P>After we run the script, this is the output seen on the screen.<\/P><IMG border=\"0\" alt=\"Image of the script's output\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/march\/hey0311\/hsg-3-11-9-2.jpg\" width=\"668\" height=\"199\"> \n<P>&nbsp;<\/P>\n<P>The <B>HResult<\/B> seen in the preceding image is either the COM or Windows error that was raised during the installation. The <B>ResultCode<\/B> is an <B>OperationResultCode<\/B> enumeration value. A <B>ResultCode<\/B> of 2 means the operation succeeded. The first set of results is returned by the <B>Download<\/B> operation, and the second set of results is returned by the <B>Install<\/B> operation. <B>Table 1<\/B> documents the result codes.<\/P>\n<TABLE id=\"EBEAC\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD>\n<TR>\n<TD class=\"tableHeader\" colSpan=\"2\">Table 1 OperationResultCode enumeration values and meanings<\/TD><\/TR>\n<TR class=\"stdHeader\" vAlign=\"top\">\n<TD id=\"colEEEAC\">Return Value<\/TD>\n<TD id=\"colEIEAC\">Meaning<\/TD><\/TR><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\">0<\/P><\/TD>\n<TD>\n<P class=\"lastInCell\">Not Started<\/P><\/TD><\/TR>\n<TR class=\"evenRecord\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\">1<\/P><\/TD>\n<TD>\n<P class=\"lastInCell\">In Progress<\/P><\/TD><\/TR>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\">2<\/P><\/TD>\n<TD>\n<P class=\"lastInCell\">Succeeded<\/P><\/TD><\/TR>\n<TR class=\"evenRecord\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\">3<\/P><\/TD>\n<TD>\n<P class=\"lastInCell\">Succeeded With Errors<\/P><\/TD><\/TR>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\">4<\/P><\/TD>\n<TD>\n<P class=\"lastInCell\">Failed<\/P><\/TD><\/TR>\n<TR class=\"evenRecord\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\">5<\/P><\/TD>\n<TD>\n<P class=\"lastInCell\">Aborted<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>If a problem occurs during the installation or download, the <B>Installation Results<\/B> object (<A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa386053(VS.85).aspx\" target=\"_blank\">IInstallationResult interface<\/A>) can at times provide information that is useful in troubleshooting the script. An example of such an error can be seen here:<\/P><IMG border=\"0\" alt=\"Image of an error that can occur if a problem occurs during installation or download\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/march\/hey0311\/hsg-3-11-9-3.jpg\" width=\"668\" height=\"331\"> \n<P>&nbsp;<\/P>\n<P>The <B>Installation Results<\/B><B>HResult<\/B> property returned from the script is documented <A href=\"http:\/\/technet.microsoft.com\/en-us\/library\/cc720442.aspx\" target=\"_blank\">on MSDN<\/A>. To interpret the results, we need to first convert the value to hexadecimal. To do this, we can use the Calculator (<B>Calc.exe<\/B>) program to make the conversion. I copy the <B>-2145124318<\/B> value from the Windows PowerShell console and paste it into Calculator. When you have done so, it looks like what you see here:<\/P><IMG border=\"0\" alt=\"Image of using Calculator to convert the value to hexadecimal\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/march\/hey0311\/hsg-3-11-9-4.jpg\" width=\"480\" height=\"309\"> \n<P>&nbsp;<\/P>\n<P>To convert the <B>HRESULT<\/B> value to something we can look up, we now need to translate the number into hexadecimal. We check hexadecimal and we also check the <B>Dword<\/B> radio button as seen here:<\/P><IMG border=\"0\" alt=\"Image of checking hexadecimal and DWord on Calculator\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/march\/hey0311\/hsg-3-11-9-5.jpg\" width=\"480\" height=\"309\"> \n<P>&nbsp;<\/P>\n<P>The resulting number 80240022 can be looked up directly in the <A href=\"http:\/\/technet.microsoft.com\/en-us\/library\/cc720442.aspx\" target=\"_blank\">MSDN documentation<\/A>, which dutifully tells us that the operation failed for all the updates. Additional information can be obtained from the System event log. The source of the event log messages will be Windows Update Agent. In the example seen in the final image below, the error that is reported is <B>0x80246007<\/B>, which means, as the same MSDN documentation tells us, that the update has not been downloaded.<\/P><IMG border=\"0\" alt=\"Image of event properties of error 0x80246007\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/march\/hey0311\/hsg-3-11-9-6.jpg\" width=\"404\" height=\"448\"> \n<P>&nbsp;<\/P>\n<P>Well, NB, that is about all there is to installing Windows Updates. I think I am going to put on my woolies and go play in the snow. It is a rare event for us to get snow at all, and to have 6 inches of the stuff? That\u2019s truly a snow day. See you tomorrow as Windows Update Week continues. Until then, peace.<\/P>\n<P>&nbsp;<\/P>\n<P><B>Ed Wilson and Craig Liebendorfer, Scripting Guys<\/B><\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! Reporting on whether a Windows Update is installed or not is pretty cool. However, what happens when I determine the update has not been applied? Am I supposed to call the user and talk them through connecting to the Microsoft Update site and choosing the appropriate update? That may work for one [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[36,3,45,380],"class_list":["post-54213","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-client-side-management","tag-scripting-guy","tag-windows-powershell","tag-windows-update"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! Reporting on whether a Windows Update is installed or not is pretty cool. However, what happens when I determine the update has not been applied? Am I supposed to call the user and talk them through connecting to the Microsoft Update site and choosing the appropriate update? That may work for one [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/54213","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=54213"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/54213\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=54213"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=54213"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=54213"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}