Here is the shell script that I used to get it done.
Version 1
Spoiler
AutoIt
#region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Compression=4 #AutoIt3Wrapper_Res_Fileversion=0.0.0.0 #AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y #AutoIt3Wrapper_Res_Language=1033 #AutoIt3Wrapper_AU3Check_Stop_OnWarning=y #AutoIt3Wrapper_Run_Tidy=y #AutoIt3Wrapper_Run_Obfuscator=y #Obfuscator_Parameters=/striponly #endregion ;**** Directives created by AutoIt3Wrapper_GUI **** #cs ---------------------------------------------------------------------------- Project Name: SystemCleanup Description: Runs a battery of tasks for annual cleanup Creation Date: 11/23/2010 AutoIt Version: v3.3.6.1 Author: David Williams (WILLICHAN) website: http://www.autoitscript.com/forum/user/6652-willichan/ #ce ---------------------------------------------------------------------------- Opt("MustDeclareVars", 1) ;0=no, 1=require pre-declare Opt("TrayAutoPause", 0) ;0=no pause, 1=Pause Opt("TrayMenuMode", 0) ;0=append, 1=no default menu, 2=no automatic check, 4=menuitemID not return Opt("TrayIconHide", 0) ;0=show, 1=hide tray icon Global Const $MyName = StringLeft(@ScriptName, StringInStr(@ScriptName, ".", 0, -1) - 1) ;get just the name portion of the script/exe name Global Const $MyMutex = $MyName & "-4C4FE209743F270A" ;name the mutex for this app. I create a new random number for each script I write to go in the quotes" Global Const $MyVersion = FileGetVersion(@ScriptFullPath) If _MutexExists($MyMutex) Then Exit ;exit if another instance of this app is running #include <Debug.au3> #include <misc.au3> Global Const $CompanyName = "WilliWare" ;Change this to whatever you want. Global Const $LogFileName = "c:\" & $MyName & ".log" ;Wherever you want it ; these next seven(7) constants are used for setting up auto-logon for reboots ;This can be a security risk if this script moves out of your own hands ;use caution Global Const $UseAutoLogin = True ;set to false if you don't want to use Global Const $mydomain = "mydomain" ;use @ComputerName for local accounts Global Const $myusername = "myusername" Global Const $mypassword = "mypassword" Global Const $LegalNoticeCaption = "Legal Notice" Global Const $LegalNoticeText = "This is my legal notice text" Global Const $DefaultDomain = "mydomain" ;This is probably the same as $mydomain, but just in case... ;;;; You only need this if one of your stages requires admin rights (which mine usually do If Not IsAdmin() Then MsgBox(48 + 262144, $MyName & " Error", "This utility requires local admin rights." & @CRLF & "Please log back in as a local administrator") Shutdown(4 + 16) EndIf ;;;; I like my scripts to be version aware. This way, thing restart from the ;;;; beginning again next year when I put out the new battery of cleanups. ;;;; I just set the AutoItWrapper to auto increment the version number. ;;;; If a new version is detected, reset and start from the beginning ;;;; if not new, pick up where we last left off Global $lastver = RegRead("HKEY_LOCAL_MACHINE\Software\" & $CompanyName, $MyName & "Version") If @error Then $lastver = "0.0.0.0" If _VersionCompare($MyVersion, $lastver) = 1 Then RegWrite("HKEY_LOCAL_MACHINE\Software\" & $CompanyName, $MyName & "Version", "REG_SZ", $MyVersion) RegWrite("HKEY_LOCAL_MACHINE\Software\" & $CompanyName, $MyName & "Stage", "REG_DWORD", 0) EndIf ;;;; Start the log file (optional If @Compiled Then FileWrite($LogFileName, $CompanyName & " " & $MyName) FileWriteLine($LogFileName, " - " & @YEAR & "." & @MON & "." & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC) Else _DebugSetup($CompanyName & " " & $MyName & " - Status") EndIf ;;;; What stage are we on? Global $stage = RegRead("HKEY_LOCAL_MACHINE\Software\" & $CompanyName, $MyName & "Stage") If @error Then $stage = 0 _SetAutoLogin() ;;;; now for the framework of the script While True ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; WARNING: The whole things ends when a number is not found, ;; ;; so don't skip any digits ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Switch $stage Case 0 _Status("Installing Application A") _InstallApplicationA() Case 1 _Status("Installing Application B") _InstallApplicationB() Case 2 _Status("Installing Application C") _InstallApplicationC() Case Else ;All Done _Status("Done") _ClearAutoLogin() Shutdown(2 + 16) ;I like to force a reboot when I am done. Comment out if you don't. Exit EndSwitch _NextStage() WEnd ;;;; put the meat and potatoes functions here. Func _InstallApplicationA() MsgBox(0, "Application A", "I am an application that does not require an immediate reboot." & @CRLF & "Let's continue without rebooting") EndFunc ;==>_InstallApplicationA Func _InstallApplicationB() ;This stage can run, re-run, and reboot all it wants, as long as you have some way to know when it is done. ;I have some stages (like Microsoft Updates) that require several reboots before done If FileExists("C:\WilliWareDemo.txt") Then Return ;have some way of checking to see if you are already done with this stage so you do not end up in a reboot loop MsgBox(0, "Application B", "I do require an immediate reboot." & @CRLF & "Let's reboot, then continue on") FileWriteLine("c:\WilliWareDemo.txt", "I am part of a demo. You can deleteme") Shutdown(2) Exit EndFunc ;==>_InstallApplicationB Func _InstallApplicationC() MsgBox(0, "Application C", "I am an application that does not require an immediate reboot." & @CRLF & "Let's continue without rebooting") EndFunc ;==>_InstallApplicationC ;;;; supporting functions are here Func _NextStage() $stage += 1 RegWrite("HKEY_LOCAL_MACHINE\Software\" & $CompanyName, $MyName & "Stage", "REG_DWORD", $stage) EndFunc ;==>_NextStage Func _SetAutoLogin() FileCreateShortcut(@ScriptFullPath, @StartupCommonDir & "\" & $MyName & ".lnk", @ScriptDir) If $UseAutoLogin Then _Status("Setting auto login") RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "Userinit", "REG_SZ", "C:\WINDOWS\system32\userinit.exe,") RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "Shell", "REG_SZ", "explorer.exe") RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultDomainName", "REG_SZ", $mydomain) RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultUserName", "REG_SZ", $myusername) RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultPassword", "REG_SZ", $mypassword) RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "AutoAdminLogon", "REG_SZ", "1") RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeCaption") RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeText") EndIf EndFunc ;==>_SetAutoLogin Func _ClearAutoLogin() FileDelete(@StartupCommonDir & "\" & $MyName & ".lnk") If $UseAutoLogin Then _Status("Clearing auto login") RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultDomainName", "REG_SZ", $DefaultDomain) RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultUserName", "REG_SZ", "") RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeCaption", "REG_SZ", $LegalNoticeCaption) RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeText", "REG_SZ", $LegalNoticeText) RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultPassword") RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "AutoAdminLogon") EndIf EndFunc ;==>_ClearAutoLogin Func _Status($msg) If @Compiled Then SplashTextOn($CompanyName & " " & $MyName & " - Status", "Stage " & $stage & ": " & $msg, 500, 100, -1, -1, 2 + 16 + 32) FileWriteLine($LogFileName, "Stage " & $stage & ": " & $msg) Else _DebugOut("Stage " & $stage & ": " & $msg) EndIf EndFunc ;==>_Status Func _MutexExists($sOccurenceName) ;Credit goes to martin for this function Local $ERROR_ALREADY_EXISTS = 183, $handle, $lastError $sOccurenceName = StringReplace($sOccurenceName, "\", "") $handle = DllCall("kernel32.dll", "int", "CreateMutex", "int", 0, "long", 1, "str", $sOccurenceName) $lastError = DllCall("kernel32.dll", "int", "GetLastError") Return $lastError[0] = $ERROR_ALREADY_EXISTS EndFunc ;==>_MutexExists
------
Here's my new version. Some people had trouble remembering not to skip numbers, or to keep them in order, so this one puts it all in an array, so you don't have to manually keep track of task IDs.
Version 2
Spoiler
AutoIt
#region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Compression=4 #AutoIt3Wrapper_Res_Fileversion=0.0.0.1 #AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y #AutoIt3Wrapper_Res_Language=1033 #AutoIt3Wrapper_AU3Check_Stop_OnWarning=y #AutoIt3Wrapper_Run_Tidy=y #AutoIt3Wrapper_Run_Obfuscator=y #Obfuscator_Parameters=/striponly #endregion ;**** Directives created by AutoIt3Wrapper_GUI **** #cs ---------------------------------------------------------------------------- Project Name: SystemCleanup Description: Runs a battery of tasks for annual cleanup Creation Date: 11/23/2010 AutoIt Version: v3.3.8.0 Author: David Williams (WILLICHAN) website: http://www.autoitscript.com/forum/user/6652-willichan/ #ce ---------------------------------------------------------------------------- If StringInStr("|WIN_2008R2|WIN_2008|WIN_2003|WIN_XPe", "|" & @OSVersion & "|") Then Exit ;don't run on servers Opt("MustDeclareVars", 1) ;0=no, 1=require pre-declare Opt("TrayAutoPause", 0) ;0=no pause, 1=Pause Opt("TrayMenuMode", 0) ;0=append, 1=no default menu, 2=no automatic check, 4=menuitemID not return Opt("TrayIconHide", 0) ;0=show, 1=hide tray icon Global Const $MyName = StringLeft(@ScriptName, StringInStr(@ScriptName, ".", 0, -1) - 1) ;get just the name portion of the script/exe name Global Const $MyMutex = $MyName & "-10371BD27CD14632" ;name the mutex for this app Global Const $MyVersion = FileGetVersion(@ScriptFullPath) If _MutexExists($MyMutex) Then Exit ;exit if another instance of this app is running Global Const $MyTitle = "System Cleanup" Global Const $MySettingsRegPath = "HKEY_LOCAL_MACHINE\Software\MadeByMe" Global Const $StageSettingRegStage = "SystemCleanupStage" Global Const $StageSettingRegVer = "SystemCleanupVersion" Global Const $LogFilePath = @DocumentsCommonDir & "\mytuneup.log" If Not IsAdmin() Then MsgBox(48 + 262144, $MyTitle & " Error", "This utility requires local admin rights." & @CRLF & @UserName & " does not have proper access to run this script." & @CRLF & "Please correct this issue and log in again.") Shutdown(4 + 16) EndIf ;;;;; ;; List tasks to be performed here ;; They will be executed in order ;; ex: _AddTask("function", "message") ;; where function is the name of the function to call that will do the work ;; and message is the message that will be displayed in the status screen ;; and/or log file. ;;;;; Global $tasklist[1][2] = [[0, 0]] _AddTask("_Task1", "Doing whatever my first task is.") _AddTask("_Task2", "This is my secont thing to accomplish. I will need to reboot.") _AddTask("_Task3", "Yet another thing to get done.") ;;;;; ;; end task list ;;;;; Func _Task1() MsgBox(0, $MyTitle, "This is task #1. No reboot required.") EndFunc ;==>_Task1 Func _Task2() If FileExists("c:\task2marker.txt") Then MsgBox(0, $MyTitle, "Looks like task #2 completed ok. Moving on.") Else MsgBox(0, $MyTitle, "This is task #2. Reboot required.") FileWriteLine("c:\task2marker.txt", "test") Shutdown(2 + 4) EndIf EndFunc ;==>_Task2 Func _Task3() MsgBox(0, $MyTitle, "This is task #3. No reboot required.") EndFunc ;==>_Task3 Global $lastver = RegRead($MySettingsRegPath, $StageSettingRegVer) If @error Then $lastver = "0.0.0.0" If _VersionCompare($MyVersion, $lastver) = 1 Then RegWrite($MySettingsRegPath, $StageSettingRegVer, "REG_SZ", $MyVersion) RegWrite($MySettingsRegPath, $StageSettingRegStage, "REG_DWORD", 0) EndIf Global $stage = RegRead($MySettingsRegPath, $StageSettingRegStage) If @error Then $stage = 0 FileWrite($LogFilePath, $MyTitle) FileWriteLine($LogFilePath, " - " & @YEAR & "." & @MON & "." & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC) _SetAutoLogin() RegWrite("HKEY_CURRENT_USER\Control Panel\Desktop", "ScreenSaveActive", "REG_SZ", 0) RegDelete("HKEY_CURRENT_USER\Control Panel\Desktop", "SCRNSAVE.EXE") While True If $stage > $tasklist[0][0] Then ;All Done _Status("Done") _ClearAutoLogin() MsgBox(64 + 262144, $MyTitle, "System cleanup has completed" & @CRLF & "Click OK to restart the system") Shutdown(2 + 4 + 16) Exit Else _Status($tasklist[$stage][1]) Call($tasklist[$stage][0]) EndIf _NextStage() WEnd Func _NextStage() $stage += 1 RegWrite($MySettingsRegPath, $StageSettingRegStage, "REG_DWORD", $stage) EndFunc ;==>_NextStage Func _SetAutoLogin() RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "Userinit", "REG_SZ", "C:\WINDOWS\system32\userinit.exe,") RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "Shell", "REG_SZ", "explorer.exe") RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultDomainName", "REG_SZ", "admindomain"); I use the machine name here for a local admin account RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultUserName", "REG_SZ", "adminlogon") RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultPassword", "REG_SZ", "adminpassword") RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "AutoAdminLogon", "REG_SZ", "1") RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeCaption") RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeText") EndFunc ;==>_SetAutoLogin Func _ClearAutoLogin() RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultDomainName", "REG_SZ", "mydomain") RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultUserName", "REG_SZ", "") RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultPassword", "REG_SZ", "") RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "AutoAdminLogon", "REG_SZ", "") RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeCaption", "REG_SZ", "LEGAL NOTICE") ; Whatever your company policy dictates here RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeText", "REG_SZ", "Legal message here") ; Whatever your company policy dictates here RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultPassword") RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "AutoAdminLogon") EndFunc ;==>_ClearAutoLogin Func _Status($msg) SplashTextOn($MyTitle & " - Status", "Stage " & $stage & ": " & $msg, 500, 100, -1, -1, 2 + 16 + 32) FileWriteLine($LogFilePath, "Stage " & $stage & ": " & $msg) EndFunc ;==>_Status Func _AddTask($task, $message) Local $tcount = $tasklist[0][0] + 1 ReDim $tasklist[$tcount + 1][2] $tasklist[0][0] = $tcount $tasklist[$tcount][0] = $task $tasklist[$tcount][1] = $message EndFunc ;==>_AddTask Func _MutexExists($sOccurenceName) ;Credit goes to martin for this function Local $ERROR_ALREADY_EXISTS = 183, $handle, $lastError $sOccurenceName = StringReplace($sOccurenceName, "\", "") $handle = DllCall("kernel32.dll", "int", "CreateMutex", "int", 0, "long", 1, "str", $sOccurenceName) $lastError = DllCall("kernel32.dll", "int", "GetLastError") Return $lastError[0] = $ERROR_ALREADY_EXISTS EndFunc ;==>_MutexExists
------
MSUpdates Module
Spoiler
This module was written for the Version 1 script, and has not been tested for Version 2.
First, you will need to download WuInstall from http://www.wuinstall.com/index.php/en/free.
(This is an excellent utility, so I highly recommend purchasing a Pro copy)
Unzip and place the WUInstall.exe file in a folder beneath your script called 3rdParty.
This module was written for the Version 1 script, and has not been tested for Version 2.
First, you will need to download WuInstall from http://www.wuinstall.com/index.php/en/free.
(This is an excellent utility, so I highly recommend purchasing a Pro copy)
Unzip and place the WUInstall.exe file in a folder beneath your script called 3rdParty.
Func _InstallWindowsUpdates() Local $DBQ = '"' Local $res Local $tfile = _TempFile(@TempDir, "~", ".exe") FileInstall("3rdParty\WUInstall.exe", $tfile, 1) $res = RunWait($tfile & " /install /criteria " & $DBQ & "IsAssigned=1 and IsHidden=0 and IsInstalled=0 and Type='Software'" & $DBQ, @TempDir) FileDelete($tfile) If $res < 2 Or $res > 4 Then Shutdown(6) EndFunc ;==>_InstallWindowsUpdates
--Edit--
Added Version 2 of script
modified log path in Version 2 (see posts 5&6)
Added MSUpdates module
Edited by willichan, 30 December 2011 - 05:43 PM.









