Table of Contents

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 WSUS Updates and windows_updates_wsus_required but sufficiently different to justify a separate entry.

The script comes in two parts,

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%"
					]

WRatzka 2013/02/06 17:42