====== wsusclient ====== The following script was developed starting from a VBScript snippet from Microsoft (source: http://msdn.microsoft.com/en-us/library/aa387102%28VS.85%29.aspx ) and serves to force installing available updates from a WSUS server. It is similar in intent to [[userspace:windows_updates|WSUS Updates]] and [[userspace:windows_updates_wsus_required|]] but sufficiently different to justify a separate entry. The script comes in two parts, * ''setup.ins'' will first install needed (on Win XP) updates for the update service itself and for windows installer. The files ''WindowsXP-KB898461-x86-ENU.exe'', ''WindowsXP-KB942288-v3-x86.exe'', and ''WindowsUpdateAgent30-x86.exe'' from Microsoft are needed for that), * ''update.ins'' will install the updates. The WSUS configuration can be controlled via properties //targetgroup// and //wsusurl//. This script has been tested on Windows XP (32bit) and Windows 7 (64bit). It has grown over time and has probably accumulated some weirdness. It should probably only be used after thorough inspection and adaptation. ===== setup.ins ===== [Actions] DefVar $NTVersion$ DefVar $ExitCode$ DefVar $WuAuVer$ DefVar $CurrentWsusUrl$ DefVar $WsusUrl$ DefVar $TargetGroup$ DefVar $NeedReboot$ DefVar $Failed$ DefVar $LogDir$ ;------------------------ Set $LogDir$ = "%SystemDrive%\tmp" ;------------------------ set $WsusUrl$ = GetProductProperty("wsusurl","http://wsus/") set $TargetGroup$ = GetProductProperty("targetgroup","") ;------------------------ set $NeedReboot$ = "False" set $Failed$ = "False" ShowBitmap "%scriptpath%\sys_wsus.png" "WSUS-Client" Set $NTVersion$ = GetNTVersion if ( $NTVersion$ = "WinXP" ) if (GetRegistryStringValue32("[HKEY_LOCAL_MACHINE\Software\HRZMR] wsusclientreboot") = "") dosinanicon_wsusclientcleanup_xp if (GetRegistryStringValue("[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\KB898461] DisplayName") = "") Message "Install Package Installer for Windows" winbatchinstall_KB898461 Sub_check_exitcode endif if (GetRegistryStringValue("[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\KB942288-v3] DisplayName") = "") Message "Install Windows Installer 4.5" winbatchinstall_KB942288-v3 Sub_check_exitcode endif set $WuAuVer$ = getValue("file version with dots", getFileInfoMap("%System%\wuauclt.exe")) if (CompareDotSeparatedNumbers("7.4.7600.226",$WuAuVer$) = "1") Message "Install Windows Update Agent 3.0" winbatchinstall_wuau Sub_check_exitcode endif if ($Failed$ = "True") LogError "Installation einer Komponente fehlgeschlagen." IsFatalError else Registry_MarkReboot comment "Fortsetzung nach Neustart" exitWindows /ImmediateReboot endif endif endif [Registry_MarkReboot] OpenKey [HKEY_LOCAL_MACHINE\Software\HRZMR] Set "wsusclientreboot"="setup" [Registry_UnmarkReboot] OpenKey [HKEY_LOCAL_MACHINE\Software\HRZMR] DeleteVar "wsusclientreboot" [winbatchinstall_KB898461] %scriptpath%\WindowsXP-KB898461-x86-ENU.exe -n -q -z [winbatchinstall_KB942288-v3] %scriptpath%\WindowsXP-KB942288-v3-x86.exe -n -q -z [winbatchinstall_wuau] %scriptpath%\WindowsUpdateAgent30-x86.exe /quiet /norestart [Sub_check_exitcode] comment "Test for installation success via exit code" set $ExitCode$ = getLastExitCode ; informations to exit codes see ; http://msdn.microsoft.com/en-us/library/aa372835(VS.85).aspx ; http://msdn.microsoft.com/en-us/library/aa368542.aspx if ($ExitCode$ = "0") comment "Looks good: setup program gives exitcode zero" else comment "Setup program gives a exitcode unequal zero: " + $ExitCode$ if ($ExitCode$ = "1605") comment "ERROR_UNKNOWN_PRODUCT 1605 This action is only valid for products that are currently installed." comment "Uninstall of a not installed product failed - no problem" else if ($ExitCode$ = "1641") comment "looks good: setup program gives exitcode 1641" comment "ERROR_SUCCESS_REBOOT_INITIATED 1641 The installer has initiated a restart. This message is indicative of a success." Set $NeedReboot$ = "True" else if ($ExitCode$ = "3010") comment "looks good: setup program gives exitcode 3010" comment "ERROR_SUCCESS_REBOOT_REQUIRED 3010 A restart is required to complete the install. This message is indicative of a success." Set $NeedReboot$ = "True" else logError "Fatal: Setup program gives an unknown exitcode unequal zero: " + $ExitCode$ Set $Failed$ = "True" endif endif endif endif [dosinanicon_wsusclientcleanup_xp] net stop wuauserv net stop bits msiexec /unregserver regsvr32 /s /u wuapi.dll regsvr32 /s /u wuaueng1.dll regsvr32 /s /u wuaueng.dll regsvr32 /s /u wucltui.dll regsvr32 /s /u wups2.dll regsvr32 /s /u wups.dll regsvr32 /s /u wuweb.dll rmdir /s /q %windir%\SoftwareDistribution reg delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate /f reg delete HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate /f if exist %windir%\WindowsUpdate.log.%date%.bak del %windir%\WindowsUpdate.log.%date%.bak if exist %windir%\WindowsUpdate.log ren %windir%\WindowsUpdate.log WindowsUpdate.log.%date%.bak msiexec /regserver regsvr32 /s wuapi.dll regsvr32 /s wuaueng1.dll regsvr32 /s wuaueng.dll regsvr32 /s wucltui.dll regsvr32 /s wups2.dll regsvr32 /s wups.dll regsvr32 /s wuweb.dll net start wuauserv ===== update.ins ===== [Actions] DefVar $NTVersion$ DefVar $ExitCode$ DefVar $WuAuVer$ DefVar $CurrentWsusUrl$ DefVar $WsusUrl$ DefVar $TargetGroup$ DefVar $CurrentTargetGroup$ DefVar $NeedReboot$ DefVar $ResultsFile$ DefVar $FoundCount$ DefVar $DownloadCount$ DefVar $NewDownloadCount$ DefVar $InstallCount$ DefVar $LogDir$ DefStringList $Results$ DefVar $winDomain$ DefVar $SystemType$ ;------------------------ Set $LogDir$ = "%SystemDrive%\tmp" ;------------------------ Set $WsusUrl$ = GetProductProperty("wsusurl","http://wsus/") sub_get_winDomain Set $TargetGroup$ = GetProductProperty("targetgroup","") If ($TargetGroup$ = "") set $TargetGroup$ = $winDomain$ Endif Set $SystemType$ = GetSystemType ;------------------------ set $NeedReboot$ = "False" set $InstallCount$ = "0" ;------------------------ ShowBitmap "%scriptpath%\sys_wsus.png" "WSUS-Client" Set $NTVersion$ = GetNTVersion Set $CurrentWsusUrl$ = GetRegistryStringValue("[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate] WUServer") ; Surprisingly GetRegistryStringValue will also read DWORD values from the ; registry and convert them to decimal strings: If GetRegistryStringValue("[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate] TargetGroupEnabled") = "1" Set $CurrentTargetGroup$ = GetRegistryStringValue("[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate] TargetGroup") Else Set $CurrentTargetGroup$ = "" Endif if not ( ($CurrentWsusUrl$ = $WsusUrl$) and ($CurrentTargetGroup$ = $TargetGroup$) ) Message "Configure WSUS client" dosinanicon_stop_wuauserv registry_wsus_passive if not ( $TargetGroup$ = "" ) registry_wsus_targetgroup endif dosinanicon_start_wuauserv endif dosinanicon_check_wuauserv If FileExists($LogDir$ + "\wuauservnotrunning") LogError "WUAUServ laeuft nicht!" isFatalError Else Set $ResultsFile$ = $LogDir$ + "\_wsus_results.log" Message "Kontaktiere WSUS " + $WsusUrl$ + "..." execwithvbs_count_updates "wscript" PASS //NoLogo //E:VBScript Set $Results$ = loadTextFile($ResultsFile$) Set $FoundCount$ = getValue("Found",$Results$) Set $DownloadCount$ = getValue("Downloaded",$Results$) Set $NewDownloadCount$ = getValue("DownloadNeeded",$Results$) If not ($FoundCount$ = "0") If not ($NewDownloadCount$ = "0") Message $NewDownloadCount$ + "/" + $FoundCount$ + " Updates müssen heruntergeladen werden..." execwithvbs_download_updates "wscript" PASS //NoLogo //E:VBScript Set $Results$ = loadTextFile($ResultsFile$) Set $FoundCount$ = getValue("Found",$Results$) Set $DownloadCount$ = getValue("DownloadCount",$Results$) Set $NewDownloadCount$ = getValue("NewDownloadCount",$Results$) Endif Message $DownloadCount$ + "/" + $FoundCount$ + " Updates heruntergeladen, installiere..." If ( $NTVersion$ = "WinXP" ) dosinanicon_stop_uphclean Endif execwithvbs_install_updates "wscript" PASS //NoLogo //E:VBScript Set $Results$ = loadTextFile($ResultsFile$) Set $FoundCount$ = getValue("Found",$Results$) Set $InstallCount$ = getValue("Installed",$Results$) Set $NeedReboot$ = getValue("NeedReboot",$Results$) If ( $NTVersion$ = "WinXP" ) dosinanicon_start_uphclean Endif Message $InstallCount$ + " von " + $FoundCount$ + " Updates installiert..." Endif If ($NeedReboot$ = "NULL") if not (GetRegistryStringValue32("[HKEY_LOCAL_MACHINE\Software\HRZMR] wsusclientreboot") = "error") LogError "Update script crashed. Will retry once after reboot..." Registry_MarkReboot_Error exitWindows /ImmediateReboot else Registry_UnMarkReboot LogError "Update script crashed AGAIN. Giving up..." isFatalError endif Else Registry_UnMarkReboot If ($NeedReboot$ = "True") comment "Fortsetzung nach Neustart" Registry_MarkReboot exitWindows /ImmediateReboot endif If not (GetRegistryStringValue("[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU] AUOptions") = "4") dosinanicon_stop_wuauserv registry_wsus_active dosinanicon_start_wuauserv Endif if ($NTVersion$ = "WinXP") dosinanicon_scrap_uninstdirs_xp endif If ($SystemType$="64 Bit System") execwith_rescan "%systemroot%\cmd64.exe" /c Else execwith_rescan "%system%\cmd.exe" /c Endif SleepSeconds 5 If Not ($InstallCount$="0") comment "We did install at least one update in this session, so let's reboot just to be safe." exitWindows /Reboot Endif Endif Endif [Registry_MarkReboot] OpenKey [HKEY_LOCAL_MACHINE\Software\HRZMR] Set "wsusclientreboot"="update" [Registry_MarkReboot_Error] OpenKey [HKEY_LOCAL_MACHINE\Software\HRZMR] Set "wsusclientreboot"="error" [Registry_UnmarkReboot] OpenKey [HKEY_LOCAL_MACHINE\Software\HRZMR] DeleteVar "wsusclientreboot" [registry_wsus_passive] openkey [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate] set "WUServer"=REG_SZ:"$WsusUrl$" set "WUStatusServer"=REG_SZ:"$WsusUrl$" set "ElevateNonAdmins"=REG_DWORD:1 set "TargetGroup"=REG_SZ:"" set "TargetGroupEnabled"=REG_DWORD:0 openkey [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU] set "ElevateNonAdmins"=REG_DWORD:1 set "NoAUShutdownOption"=REG_DWORD:0 set "NoAUAsDefaultShutdownOption"=REG_DWORD:0 set "UseWUServer"=REG_DWORD:1 set "RescheduleWaitTimeEnabled"=REG_DWORD:1 set "RescheduleWaitTime"=REG_DWORD:1 set "NoAutoRebootWithLoggedOnUsers"=REG_DWORD:0 set "DetectionFrequencyEnabled"=REG_DWORD:1 set "DetectionFrequency"=REG_DWORD:6 set "AutoInstallMinorUpdates"=REG_DWORD:1 set "RebootWarningTimeoutEnabled"=REG_DWORD:1 set "RebootWarningTimeout"=REG_DWORD:30 set "RebootRelaunchTimeoutEnabled"=REG_DWORD:1 set "RebootRelaunchTimeout"=REG_DWORD:120 set "NoAutoUpdate"=REG_DWORD:0 set "ScheduledInstallDay"=REG_DWORD:0 set "ScheduledInstallTime"=REG_DWORD:3 set "AUOptions"=REG_DWORD:2 [registry_wsus_targetgroup] openkey [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate] set "TargetGroupEnabled"=REG_DWORD:1 set "TargetGroup"=REG_SZ:"$TargetGroup$" [registry_wsus_active] openkey [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU] set "AUOptions"=REG_DWORD:4 [dosinanicon_stop_wuauserv] net stop wuauserv [dosinanicon_start_wuauserv] net start wuauserv [dosinanicon_check_wuauserv] sc query wuauserv|find "RUNNING" if errorlevel 1 goto REPAIR goto DONE :REPAIR regsvr32 /s wuapi.dll regsvr32 /s wuaueng1.dll regsvr32 /s wuaueng.dll regsvr32 /s wucltui.dll regsvr32 /s wups2.dll regsvr32 /s wups.dll regsvr32 /s wuweb.dll net start wuauserv sc query wuauserv|find "RUNNING" if errorlevel 1 goto FAIL :DONE del $LogDir$\wuauservnotrunning goto END :FAIL copy NUL $LogDir$\wuauservnotrunning :END [dosinanicon_stop_uphclean] net stop uphclean [dosinanicon_start_uphclean] net start uphclean [execwith_rescan] wuauclt.exe /detectnow wuauclt.exe /reportnow [dosinanicon_scrap_uninstdirs_xp] setlocal cd /d %windir% attrib -h $NtUn* /d /s for /d %%d in ($NtUn*) do rmdir /s /q %%d endlocal [execwithvbs_count_updates] rem This is derived from: rem http://msdn.microsoft.com/en-us/library/aa387102(VS.85).aspx rem "Searching, Downloading, and Installing Updates" On Error Resume Next dim fso : Set fso = CreateObject("Scripting.FileSystemObject") dim Results: Set Results = fso.CreateTextFile("$ResultsFile$",True,False) rem Results will contain return values to be read into a String List Set wuS = CreateObject("Microsoft.Update.Session") Set updateSearcher = wuS.CreateupdateSearcher() Set searchResult = updateSearcher.Search("IsInstalled=0 and Type='Software'") downloaded=0 downloadneeded=0 found = searchResult.Updates.Count For I = 0 To found-1 Set update = searchResult.Updates.Item(I) If update.IsDownloaded = true Then downloaded = downloaded + 1 Else downloadneeded = downloadneeded + 1 End If Next Results.WriteLine "Found=" & found Results.WriteLine "Downloaded=" & downloaded Results.WriteLine "DownloadNeeded=" & downloadneeded Results.Close WScript.Quit [execwithvbs_download_updates] rem This is derived from: rem http://msdn.microsoft.com/en-us/library/aa387102(VS.85).aspx rem "Searching, Downloading, and Installing Updates" On Error Resume Next dim fso : Set fso = CreateObject("Scripting.FileSystemObject") dim Results: Set Results = fso.CreateTextFile("$ResultsFile$",True,False) rem Results will contain return values to be read into a String List Set wuS = CreateObject("Microsoft.Update.Session") Set updateSearcher = wuS.CreateupdateSearcher() Set searchResult = updateSearcher.Search("IsInstalled=0 and Type='Software'") found = searchResult.Updates.Count Set updatesToDownload = CreateObject("Microsoft.Update.UpdateColl") olddownloads=0 For I = 0 To found-1 Set update = searchResult.Updates.Item(I) If update.IsDownloaded = true Then olddownloads = olddownloads + 1 Else updatesToDownload.Add(update) End If Next Set downloader = wuS.CreateUpdateDownloader() downloader.Updates = updatesToDownload downloader.Download() downloaded = 0 For I = 0 To found-1 set update = searchResult.Updates.Item(I) If update.IsDownloaded = true Then downloaded = downloaded + 1 End If Next Results.WriteLine "Found=" & found Results.WriteLine "DownloadCount=" & downloaded Results.WriteLine "NewDownloadCount=" & ( downloaded - olddownloads ) Results.Close WScript.Quit [execwithvbs_install_updates] rem This is derived from: rem http://msdn.microsoft.com/en-us/library/aa387102(VS.85).aspx rem "Searching, Downloading, and Installing Updates" On Error Resume Next dim fso : Set fso = CreateObject("Scripting.FileSystemObject") dim Results: Set Results = fso.CreateTextFile("$ResultsFile$",True,False) rem Results will contain return values to be read into a String List Set wuS = CreateObject("Microsoft.Update.Session") Set updateSearcher = wuS.CreateupdateSearcher() Set searchResult = updateSearcher.Search("IsInstalled=0 and Type='Software'") found = searchResult.Updates.Count Set wuC = CreateObject("Microsoft.Update.UpdateColl") downloaded=0 For I = 0 To found-1 set update = searchResult.Updates.Item(I) If update.IsDownloaded = true Then downloaded=downloaded+1 wuC.Add(update) End If Next Set installer = wuS.CreateUpdateInstaller() installer.Updates = wuC Set installationResult = installer.Install() installed = 0 For I = 0 to wuC.Count - 1 if installationResult.GetUpdateResult(I).ResultCode = 2 Then installed = installed + 1 end if Next Results.WriteLine "Found=" & downloaded Results.WriteLine "Installed=" & installed If installationResult.RebootRequired Then Results.WriteLine "NeedReboot=True" Else Results.WriteLine "NeedReboot=False" End If rem We need to do this as conversion of bools to text is localized, rem so we would sometimes get "Wahr" or "Falsch" instead of "True" and "False". Results.Close WScript.Quit [sub_get_winDomain] markErrorNumber opsiservicecall_authenticated if errorsOccuredSinceMark > 0 comment "nicht authentisiert" set $winDomain$ = "" else Set $Results$ = getReturnListFromSection('opsiservicecall_getGeneralConfig_hash') set $winDomain$ = getValue("clientconfig.windows.domain",$Results$) endif [opsiservicecall_authenticated] "method": "authenticated" "params": [ ] [opsiservicecall_getGeneralConfig_hash] "method": "getGeneralConfig_hash" "params": [ "%HostID%" ] --- //[[ratzka@hrz.uni-marburg.de|WRatzka]] 2013/02/06 17:42//