cherdeg Posted June 24, 2009 Share Posted June 24, 2009 Hi!We're currently using the CUI script below to windowsupdate newly provisioned VMs. Basically it works just perfect (although it's a bit talkative), but there is one serious drawback: When using it on a new system that is currently not updated to the latest ServicePack, the script of course installs that "Patch" also. Problem: A ServicePack requires interaction when installed this way. Goal is to avoid this. I know that I could install a ServicePack silently using the parameters "/quiet /norestart" - but therefore I had to start its executable seperately (which is, what you'll probably have guessed by now, is not desired). Does anyone of you know a way to avoid that interaction?expandcollapse popup;#################################################################### ;# ;# Christoph Herdeg, May 2009 ;# http://www.cs-it-solutions.de ;# ;#################################################################### ; Define the include files ; ================================================================================================== #include <array.au3> ; Hide the damn Tray-Icon that nobody needs ; ================================================================================================== #NoTrayIcon ; Read the UpdateIDs of all unwanted Packages from the INI-File ; ================================================================================================== $s_IniFile = @ScriptDir & "\" & "Patchit.ini" $a_UnwantedPatches = IniReadSection($s_IniFile, "unwanted") Local $a_tmpUnwantedPatches[UBound($a_UnwantedPatches)] For $i_i=0 to UBound($a_UnwantedPatches) -1 $a_tmpUnwantedPatches[$i_i] = $a_UnwantedPatches[$i_i][1] Next $a_UnwantedPatches = $a_tmpUnwantedPatches $s_UnwantedPatches = _ArrayToString($a_UnwantedPatches, "*") $s_UnwantedPatches = StringReplace($s_UnwantedPatches, "*", "' and UpdateID != '") $s_UnwantedPatches = StringTrimLeft($s_UnwantedPatches, 2) $s_UnwantedPatches = $s_UnwantedPatches & "'" ; Opt in for the "Microsoft Update" Service, GUID ; ================================================================================================== ConsoleWrite("Enabling Microsoft Update..." & @CRLF) $o_ServiceManager = ObjCreate("Microsoft.Update.ServiceManager") $o_ServiceManager.ClientApplicationID = "My App" $o_NewUpdateService = $o_ServiceManager.AddService2("7971f918-a847-4430-9279-4a52d1efe18d",7,"") ; Create the COM-Object for Microsoft-Update ; ================================================================================================== ConsoleWrite("Creating COM-Object for Microsoft Update..." & @CRLF & @CRLF) $o_updateSession = ObjCreate("Microsoft.update.Session") ; Start to search for approved Updates on the Windowsupdate-Source defined ; ================================================================================================== ConsoleWrite("Searching for updates, please wait..." & @CRLF) $o_updateSearcher = $o_updateSession.CreateupdateSearcher() ; Create an object containing the list of applicable Updates...if there are none, exit ; (The packages for Windows Search 4.0, the Office Live-Add-Ins and Windows Live Essentials are ; being excluded due to their impossibly high crappiness factor) ; ================================================================================================== $o_searchResult = $o_updateSearcher.Search("IsInstalled=0 and Type='Software' and IsHidden=0 " & $s_UnwantedPatches) ConsoleWrite("The applicable updates for this machine are:" & @CRLF & @CRLF) For $i_i = 0 To $o_searchResult.Updates.Count - 1 $s_update = $o_searchResult.Updates.Item($i_i) ConsoleWrite($i_i + 1 & "> " & $s_update.Title & @CRLF) Next If $o_searchResult.Updates.Count = 0 Then ConsoleWrite("...there are no applicable updates. Your system is up-to-date!" & @CRLF) Exit EndIf ; Create an object list containing the list of Updates to download ; ================================================================================================== ConsoleWrite(@CRLF & "Creating collection of updates to download:" & @CRLF & @CRLF) $s_updatesToDownload = ObjCreate("Microsoft.update.UpdateColl") For $i_i = 0 To $o_searchResult.Updates.Count - 1 $s_update = $o_searchResult.Updates.Item($i_i) ConsoleWrite($i_i + 1 & "> adding: " & $s_update.Title & @CRLF) $s_updatesToDownload.Add($s_update) Next ; Do the download using the object list created above ; ================================================================================================== ConsoleWrite(@CRLF & "Downloading updates..." & @CRLF) $o_downloader = $o_updateSession.CreateUpdateDownloader() $o_downloader.Updates = $s_updatesToDownload $o_downloader.Download() ConsoleWrite(@CRLF & "List of downloaded updates:" & @CRLF) For $i_i = 0 To $o_searchResult.Updates.Count - 1 $s_update = $o_searchResult.Updates.Item($i_i) If $s_update.IsDownloaded Then ConsoleWrite($i_i + 1 & "> " & $s_update.Title & @CRLF) EndIf Next ; Create an object list containing the list of Updates to install ; ================================================================================================== ConsoleWrite(@CRLF & "Creating collection of downloaded updates to install:" & @CRLF & @CRLF) $o_updatesToInstall = ObjCreate("Microsoft.update.UpdateColl") For $i_i = 0 To $o_searchResult.Updates.Count - 1 $s_update = $o_searchResult.Updates.Item($i_i) If $s_update.IsDownloaded = True Then ConsoleWrite($i_i + 1 & "> adding: " & $s_update.Title & @CRLF) $o_updatesToInstall.Add($s_update) EndIf Next ; Do the installation using the object list created above ; ================================================================================================== ConsoleWrite(@CRLF & "Installing updates..." & @CRLF & @CRLF) $i_installer = $o_updateSession.CreateUpdateInstaller() $i_installer.Updates = $o_updatesToInstall If $o_updatesToInstall.Count > 0 Then $o_installationResult = $i_installer.Install() ; Output results of install ConsoleWrite("Installation Result: " & $o_installationResult.ResultCode & @CRLF) ConsoleWrite("Listing of updates installed " & "and individual installation results:" & @CRLF & @CRLF) For $i_i = 0 To $o_updatesToInstall.Count - 1 ConsoleWrite($i_i + 1 & "> " & $o_updatesToInstall.Item($i_i).Title & ": " & $o_installationResult.GetUpdateResult($i_i).ResultCode & @CRLF) Next Else ConsoleWrite(@CRLF & "Nothing to install!" & @CRLF & @CRLF) EndIf ; Restart the "Automatic Updates" Service ; ================================================================================================== ConsoleWrite(@CRLF & "Restarting the Windows Update Service" & @CRLF) RunWait(@SystemDir & "\net.exe stop wuauserv", "", @SW_HIDE) sleep(2000) RunWait(@SystemDir & "\net.exe start wuauserv", "", @SW_HIDE) ; Detect and report the current patchstate to a WSUS server if present ; ================================================================================================== ConsoleWrite(@CRLF & "Executing wuauctl /detectnow" & @CRLF) RunWait(@SystemDir & "\wuauctl /detectnow", "", @SW_HIDE) sleep(2000) ConsoleWrite(@CRLF & "Executing wuauctl /reportnow" & @CRLF & @CRLF) RunWait(@SystemDir & "\wuauctl /reportnow", "", @SW_HIDE)BTW.: If you give the "Specify intranet Microsoft update service location"-local policy a working value, the script will use that WSUS instead of http://update.microsoft.com.Regards,Chris Link to comment Share on other sites More sharing options...
storme Posted June 24, 2009 Share Posted June 24, 2009 G'day cherdeg Very nice bit of code you have there. I've written my own updater that uses "autopatcher" to load all the individual updates and saved myself downloading the same update over and over for different computers. But it doesn't load the service packs so I've resorted to the brute force method below. It maybe worth tacking something like this on to the start of your code to load the patches then execute your more elegant method for the individual patches. If StringRight(@OSServicePack, 1) < 3 Then ;MsgBox(0, "Service pack", "@OSServicePack = " & StringRight(@OSServicePack, 1)) writeLog("LOAD SP3") ; LOAD SP3 $ExitCode = RunWait(@ScriptDir & '\UPDATER-Files\SP3\WindowsXP-KB936929-SP3-x86-ENU.exe /S', @TempDir) If @error Then writeLog("ERROR: " & $UpdateStage & " Exit Code = " & $ExitCode) MsgBox(0, "ERROR: RunWait " & $UpdateStage, "Stage = " & $UpdateStage & @CR & "Exit Code = " & $ExitCode) Exit EndIf Reboot(30) ; restart EndIf I am curious what you have in your "Patchit.ini" file. Any chance of getting you to post it? BTW I agree with your view on "Windows Search 4.0, the Office Live-Add-Ins and Windows Live Essentials". I've had so much trouble with them on customers computers...sigh Good Luck John Morrison Some of my small contributions to AutoIt Browse for Folder Dialog - Automation SysTreeView32 | FileHippo Download and/or retrieve program information | Get installedpath from uninstall key in registry | RoboCopy function John Morrison aka Storm-E Link to comment Share on other sites More sharing options...
cherdeg Posted June 25, 2009 Author Share Posted June 25, 2009 (edited) Very nice bit of code you have there.Thanks-a-lot "for them flowers" I am curious what you have in your "Patchit.ini" file. Any chance of getting you to post it?Yes of course...getting rid of "the pest" is quite easy...here's the INI-File: CODE[unwanted] ; Windows Live Essentials ID1=9514bb43-f49d-499b-a655-9d64caf68976 ; Office Live Add-Ins ID2=af5c516f-1764-4dc0-b1e9-1e20dbee815c ; Windows Search 4.0 ID3=f1b1a591-bb75-4b1c-9fbd-03eedb00cc9dIf nobody else comes up with something, e.g. a switch/parameter, to control $i_installer.Install() to install everything unattended (btw. IE8 would be another problematic package), probably I'll modify and use your idea... 1. get Update IDs of all SPs and exclude them via the INI-File 2. check which OS and which currently installed SP 3. read from INI-File which is the latest SP for respective OS and if it is already installed set a Registry Key for the updater to execute after next login and reboot 4. IF NO THEN install separately from local repository, install RunOnce 5. IF YES THEN do the "default" updating Your opinion? Best Regards, Chris EDIT: Btw., I use the executable from my 1st post in conjunction with psexec over hosts drawn from our AD to update them remotely. Cool? Like it? Edited June 25, 2009 by cherdeg Link to comment Share on other sites More sharing options...
cherdeg Posted June 25, 2009 Author Share Posted June 25, 2009 (edited) For the people interested in this topic here the UpdateIDs our WSUS reports for the different ServicePacks: ; Latest Service Packs ; ============================== ; Windows Server 2000 Service Pack 4 (32-Bit x86) SPID1=b91f8a5d-56f6-4e5c-b7c0-fd95360f7a27 ; Windows XP Service Pack 3 (32-Bit x86) SPID2=34b52415-a5ba-41e9-8072-9d2dee8b22a9 ; Windows XP Service Pack 3 (64-Bit x64) ; SPID3=No ID yet because XPx64SP3 = W2K3x64SP3 ; Windows Server 2003 Service Pack 2 (32-Bit x86) ; SPID=5c23105e-2007-449d-b9c0-5f60735df63b (???) SPID4=9452503c-05be-4a64-99ed-9a59f7d65398 ; Windows Server 2003 Service Pack 2 (64-Bit x64) SPID5=a024086f-17fd-4875-8d84-a5d9a6811ed4 ; Windows Vista Service Pack 2 (32-Bit x86) SPID6=cad30b29-e5a2-42ed-bcdc-501208b47b91 ; Windows Vista Service Pack 2 (64-Bit x64) SPID7=ba19a750-2fab-41c5-ab41-822c4373974d ; Windows Server 2008 Service Pack 2 (32-Bit x86) SPID8=363855a3-39b4-4b6e-944e-da8ccea428d7 ; Windows Server 2008 Service Pack 2 (64-Bit x64) SPID9=56e25ed4-8d4a-4e8c-81d8-cc71983c58e0 Please note that I found two Versions of Windows Server 2003 Service Pack 2 (32-Bit x86) on our WSUS (which disturbs me a bit). Therefore there are also two UpdateIDs: 5c23105e-2007-449d-b9c0-5f60735df63b (430 hits on google) and 9452503c-05be-4a64-99ed-9a59f7d65398 (5080 hits on google). I have no clue why - maybe one of you guys has? EDIT: Corrected typo in UID of Windows Server 2003 Service Pack 2 (64-Bit x64). Edited June 25, 2009 by cherdeg Link to comment Share on other sites More sharing options...
storme Posted June 26, 2009 Share Posted June 26, 2009 Thanks-a-lot "for them flowers" Yes of course...getting rid of "the pest" is quite easy...here's the INI-File:Thanks! Sorry for not getting back sooner. My interenet was down for a couple of days... If nobody else comes up with something, e.g. a switch/parameter, to control $i_installer.Install() to install everything unattended (btw. IE8 would be another problematic package), probably I'll modify and use your idea...I'd definatle take a look a "autopatcher". I use it to save on all the downloads but they also look at interactions and save me a lot of heart ache. As all the machines I update are in my work shop it's a lot quicker to have all the files on hand. They have included IE8 in the latest update so it even does that.1. get Update IDs of all SPs and exclude them via the INI-File2. check which OS and which currently installed SP3. read from INI-File which is the latest SP for respective OS and if it is already installed set a Registry Key for the updater to execute after next login and reboot4. IF NO THEN install separately from local repository, install RunOnce 5. IF YES THEN do the "default" updatingJust a suggestion.In step 1 check if a SP is in the list of updates.If it is then load it from the local repository Set auto restart after load to run the script again and check for updates - I do this in my script.If there are no SPs then do regular updatesEDIT: Btw., I use the executable from my 1st post in conjunction with psexec over hosts drawn from our AD to update them remotely. Cool? Like it? sounds good. I love AutoIT the more I use it more I love it. John Morrison Some of my small contributions to AutoIt Browse for Folder Dialog - Automation SysTreeView32 | FileHippo Download and/or retrieve program information | Get installedpath from uninstall key in registry | RoboCopy function John Morrison aka Storm-E Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now