'******************************************************************************* ' Name: OffScrub_O15c2r.vbs ' Author: Microsoft Customer Support Services ' Copyright (c) 2012 Microsoft Corporation ' Script to remove Office 2013 Click To Run (C2R) products ' when a regular uninstall is no longer possible '******************************************************************************* Option Explicit '------------------------------------------------------------------------------- ' ' Declaration of constants '------------------------------------------------------------------------------- Const DLGTITLE = "Microsoft IT Office 2013 Cleanup Utility" Const CSVLOGFOLDER = "\\hotorange\logs$\Removal\" Const SCRIPTVERSION = "v1.71" Const SCRIPTFILE = "OffScrub_O15.vbs" Const SCRIPTNAME = "OffScrub_O15" Const RETVALFILE = "ScrubRetValFile.txt" Const OVERSION = "15.0" Const OVERSIONMAJOR = "15" Const OREGREF = "OFFICE15." Const OREGREFC2R = "Microsoft Office 15" Const ONAME = "Office 2013 C2R" Const OFFICEID = "000000FF1CE}" Const HKCR = &H80000000 Const HKCU = &H80000001 Const HKLM = &H80000002 Const HKU = &H80000003 Const PRODLEN = 12 Const SQUISHED = 20 Const COMPRESSED = 32 Const REG_ARP = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" Const VB_YES = 6 Const VB_NO = 7 Const ERROR_SUCCESS = 0 'Bit #1. 0 indicates Success. Script completed successfully Const ERROR_FAIL = 1 'Bit #1. Failure bit. Indicates an overall script failure. 'RESERVED bit! Returned when process is killed from task manager Const ERROR_REBOOT_REQUIRED = 2 'Bit #2. Reboot bit. If set a reboot is required Const ERROR_USERCANCEL = 4 'Bit #3. User Cancel bit. Controlled cancel from script UI Const ERROR_STAGE1 = 8 'Bit #4. Informational. Msiexec based install was not possible Const ERROR_STAGE2 = 16 'Bit #5. Critical. Not all of the intended cleanup operations could be applied Const ERROR_INCOMPLETE = 32 'Bit #6. Removal needs to run again after a system reboot. Const ERROR_DCAF_FAILURE = 64 'Bit #7. Critical. Da capo al fine (second attempt) still failed. Const ERROR_ELEVATION_USERDECLINED = 128 'Bit #8. Critical script error. User declined to allow mandatory script elevation Const ERROR_ELEVATION = 256 'Bit #9. Critical script error. The attempt to elevate the process did not succeed Const ERROR_SCRIPTINIT = 512 'Bit #10. Critical script error. Initialization failed Const ERROR_RELAUNCH = 1024'Bit #11. Critical script error. This is a temporary value and must not be the final return code Const ERROR_UNKNOWN = 2048'Bit #12 Critical script error. Script did not complete in a well defined state Const ERROR_ALL = 4095'Full BitMask Const ERROR_USER_ABORT = &HC000013A 'RESERVED. Dec -1073741510. Critical error. Returned when user aborts with + or closes the cmd window Const ERROR_SUCCESS_CONFIG_COMPLETE = 1728 Const ERROR_SUCCESS_REBOOT_REQUIRED = 3010 Const COL_USERNAME = 0 'A Const COL_COMPUTERNAME = 1 'B Const COL_DATETIME = 2 'C Const COL_SCRIPTVERSION = 3 'D Const COL_RESULT = 4 'E Const COL_WINOS = 5 'F Const COL_WINVERSION = 6 'G Const COL_WINARCHITECTURE = 7 'H Const COL_REMOVALTIMEINSECONDS = 8 'I Const COL_REBOOTREQUIRED = 9 'J Const COL_REBOOTED = 10'K Const COLMAX = 10 '------------------------------------------------------------------------------- ' ' Declaration of variables '------------------------------------------------------------------------------- Dim oFso, oMsi, oReg, oWShell, oWmiLocal, oShellApp Dim ComputerItem, Item, LogStream, TmpKey Dim arrVersion Dim dicKeepProd, dicKeepLis, dicApps, dicKeepFolder, dicDelRegKey, dicKeepReg Dim dicInstalledSku, dicRemoveSku, dicKeepSku, dicC2RSuite, dicDelInUse Dim dicDelFolder Dim sAppData, sScrubDir, sProgramFiles, sProgramFilesX86, sCommonProgramFiles Dim sAllusersProfile, sOSVersion, sWinDir, sWICacheDir, sCommonProgramFilesX86 Dim sProgramData, sPackageFolder, sLocalAppData, sOInstallRoot, sSkuRemoveList Dim sOSinfo, sDefault, sTemp, sTmp, sCmd, sLogDir, sPrompt, sProfilesDirectory Dim sRetVal, sScriptDir, sPackageGuid Dim iVersionNT, iError, iProcCloseCnt Dim f64, fLogInitialized, fNoCancel, fRemoveOse, fDetectOnly, fQuiet, fForce Dim fC2R, fRemoveAll, fRebootRequired, fRerun, fSetRunOnce, fTestRerun Dim fIsElevated, fNoElevate, fUserConsent Dim arrResult Dim tStart, tEnd '------------------------------------------------------------------------------- ' Main ' ' Main section of script '------------------------------------------------------------------------------- ' initialize required settings and objects ' ---------------------------------------- Initialize ' call the command line parser '----------------------------- ParseCmdLine ' get user consent to clean O15 products ' -------------------------------------- sPrompt = vbTab & "Are you sure to run a full CleanUp for Office 2013?" & vbCrLf & vbCrLf & _ vbTab & "Click 'No' to cancel." & vbCrLf & vbCrLf & _ "WARNING: If you click 'Yes' this will remove ALL installed Office 2013 applications!" If MsgBox(sPrompt, 292, DLGTITLE) = VB_NO Then SetError ERROR_USERCANCEL ExitScript End If ' get start time tStart = Time() '----------------------------- ' Stage # 0 - Basic detection | '----------------------------- sTmp = "Stage # 0 " & chr(34) & "Basic detection" & chr(34) & " (" & Time & ")" Log vbCrLf & sTmp & vbCrLf & String(Len(sTmp), "=") & vbCrLf ' ensure integrity of WI metadata which could fail used APIs otherwise '--------------------------------------------------------------------- Log "Ensure Windows Installer metadata integrity " & " (" & Time & ")" EnsureValidWIMetadata HKCU,"Software\Classes\Installer\Products", COMPRESSED EnsureValidWIMetadata HKCR,"Installer\Products", COMPRESSED EnsureValidWIMetadata HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products", COMPRESSED EnsureValidWIMetadata HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components", COMPRESSED EnsureValidWIMetadata HKCR,"Installer\Components", COMPRESSED ' undo FCI workaround If iVersionNT > 601 Then On Error Resume Next sProgramData = oWSHell.ExpandEnvironmentStrings("%programdata%") If oFso.FolderExists(sProgramData & "\Microsoft\FCI") Then sCmd = "icacls.exe " & chr(34) & sProgramData & "\Microsoft\FCI" & chr(34) & " /remove:d *S-1-1-0" Log "Remove deny on FCI folder by calling:" Log " " & sCmd sRetVal = oWShell.Run(sCmd, 0, False) Log "icacls returned: " & sRetVal sCmd = "icacls.exe " & chr(34) & sProgramData & "\Microsoft\FCI" & chr(34) & " /grant *S-1-5-32-544:(OI)(CI)R" Log "Grant permission on FCI folder by calling:" Log " " & sCmd sRetVal = oWShell.Run(sCmd, 0, False) Log "icacls returned: " & sRetVal End If On Error Goto 0 End If ' build a list with installed/registered Office products '------------------------------------------------------- FindInstalledOProducts If dicC2RSuite.Count > 0 Then Log "Registered product(s) found:" For Each Item in dicC2RSuite.Items Log " - " & Item Next 'Item Else Log "No registered product(s) found" End If ' locate the C2R %PackageFolder% and the PackageGuid '--------------------------------------------------- RegReadValue HKLM, "SOFTWARE\Microsoft\Office\15.0\ClickToRun", "PackageFolder", sPackageFolder, "REG_SZ" ' if sPackageFolder is invalid set it to the c2r registry reference string If NOT Len(sPackageFolder) > 0 OR IsNull(sPackageFolder) Then sPackageFolder = OREGREFC2R sPackageGuid = "" RegReadValue HKLM, "SOFTWARE\Microsoft\Office\15.0\ClickToRun", "PackageGUID", sPackageGuid, "REG_SZ" ' Init complete. Reset the return value '-------------------------------------- ClearError ERROR_SCRIPTINIT '----------------------- ' Stage # 1 - Uninstall | '----------------------- sTmp = "Stage # 1 " & chr(34) & "Uninstall" & chr(34) & " (" & Time & ")" Log vbCrLf & sTmp & vbCrLf & String(Len(sTmp), "=") & vbCrLf ' clean O15 SPP '-------------- Log vbCrLf & "Clean OSPP" & " (" & Time & ")" CleanO15SPP ' end all running Office applications '------------------------------------ Log vbCrLf & "End running processes" & " (" & Time & ")" CloseOfficeApps ' remove scheduled tasks which might interfere with uninstall '------------------------------------------------------------ DelSchtasks ' unpin shortcuts '---------------- Log vbCrLf & "Unpinning shortcuts" & " (" & Time & ")" CleanShortcuts sAllUsersProfile, False, True CleanShortcuts sProfilesDirectory, False, True ' uninstall '---------- Log vbCrLF & "Removing " & ONAME & " (" & Time & ")" Uninstall '--------------------- ' Stage # 2 - CleanUp | '--------------------- sTmp = "Stage # 2 " & chr(34) & "CleanUp" & chr(34) & " (" & Time & ")" Log vbCrLf & sTmp & vbCrLf & String(Len(sTmp), "=") & vbCrLf ' Cleanup registry data '---------------------- RegWipe ' Cleanup files '-------------- FileWipe ' for test purposes only! If fTestRerun Then Log vbCrLf & "Enforcing 'Rerun' mode for test purposes" fRebootRequired = True SetError ERROR_REBOOT_REQUIRED Rerun End If ExitScript Sub ExitScript '------------------ ' Stage # 3 - Exit | '------------------ ' Update cached error and quit '----------------------------- If NOT CBool(iError AND (ERROR_FAIL + ERROR_INCOMPLETE)) Then RegDeleteValue HKCU, "SOFTWARE\Microsoft\Office\15.0\CleanC2R", "Rerun", False SetRetVal iError ' log result If CBool(iError AND ERROR_INCOMPLETE) Then Log vbCrLf & "Removal result: " & iError & " - INCOMPLETE. Uninstall requires a system reboot to complete." arrResult(COL_RESULT) = iError & " - SUCCESS_REBOOT_REQUIRED" Else sTmp = " - SUCCESS" If CBool(iError AND ERROR_USERCANCEL) Then sTmp = " - USER CANCELED" If CBool(iError AND ERROR_FAIL) Then sTmp = " - FAIL" arrResult(COL_RESULT) = iError & sTmp Log vbCrLf & "Removal result: " & iError & sTmp End If If CBool(iError AND ERROR_FAIL) Then If CBool(iError AND ERROR_REBOOT_REQUIRED) Then Log " - Reboot required" If CBool(iError AND ERROR_USERCANCEL) Then Log " - User cancel" If CBool(iError AND ERROR_STAGE1) Then Log " - Msiexec failed" If CBool(iError AND ERROR_STAGE2) Then Log " - Cleanup failed" If CBool(iError AND ERROR_INCOMPLETE) Then Log " - Removal incomplete. Rerun after reboot needed" If CBool(iError AND ERROR_DCAF_FAILURE) Then Log " - Second attempt cleanup still incomplete" If CBool(iError AND ERROR_ELEVATION_USERDECLINED) Then Log " - User declined elevation" If CBool(iError AND ERROR_ELEVATION) Then Log " - Elevation failed" If CBool(iError AND ERROR_SCRIPTINIT) Then Log " - Initialization error" If CBool(iError AND ERROR_RELAUNCH) Then Log " - Unhandled error during relaunch attempt" If CBool(iError AND ERROR_UNKNOWN) Then Log " - Unknown error" ' ERROR_USER_ABORT is only valid for the temporary cached error file 'If CBool(iError AND ERROR_USER_ABORT) Then Log " - Process terminated by user" End If Log vbCrLf & "Removal end: " & vbTab & Time ' capture elapsed time tEnd = Time() arrResult(COL_REMOVALTIMEINSECONDS) = Int((tEnd - tStart) * 1000000 + 0.5) / 10 If arrResult(COL_REMOVALTIMEINSECONDS) < 0 Then arrResult(COL_REMOVALTIMEINSECONDS) = arrResult(COL_REMOVALTIMEINSECONDS) + 86400 If CBool(iError AND ERROR_USERCANCEL) Then arrResult(COL_REMOVALTIMEINSECONDS) = 0 ' Reboot handling If fRebootRequired Then arrResult(COL_REBOOTREQUIRED) = "True" arrResult(COL_REBOOTED) = "True" sPrompt = "In order to complete uninstall, a system reboot is necessary. Would you like to reboot now?" If MsgBox(sPrompt, vbYesNo, DLGTITLE) = VB_YES Then CsvWrite sCmd = "Shutdown /r /t 0" oWShell.Run sCmd, 0, False Else 'If fSetRunOnce Then SetRunOnce arrResult(COL_REBOOTED) = "False" CsvWrite End If Else arrResult(COL_REBOOTREQUIRED) = "False" CsvWrite End If wscript.quit iError End Sub 'ExitScript '------------------------------------------------------------------------------- ' End Main ' ' End of Main section '------------------------------------------------------------------------------- '------------------------------------------------------------------------------- ' Initialize ' ' Configure defaults and initialize all required objects '------------------------------------------------------------------------------- Sub Initialize () Dim iCnt ' set defaults '------------- iError = ERROR_SUCCESS iProcCloseCnt = 0 sLogDir = "" sPackageFolder = "" f64 = False fLogInitialized = False fNoCancel = False fRemoveOse = False fDetectOnly = False fQuiet = False fForce = False fC2R = True fRebootRequired = False fRerun = False fTestRerun = False fIsElevated = False fNoElevate = False fSetRunOnce = False fUserConsent = False ReDim arrResult(COLMAX) For iCnt = 0 To COLMAX arrResult(iCnt) = "" Next ' create required objects '------------------------ Set oWmiLocal = GetObject("winmgmts:\\.\root\cimv2") Set oWShell = CreateObject("Wscript.Shell") Set oShellApp = CreateObject("Shell.Application") Set oFso = CreateObject("Scripting.FileSystemObject") Set oMsi = CreateObject("WindowsInstaller.Installer") Set oReg = GetObject("winmgmts:\\.\root\default:StdRegProv") ' get environment path values '---------------------------- sAppData = oWShell.ExpandEnvironmentStrings("%appdata%") sLocalAppData = oWShell.ExpandEnvironmentStrings("%localappdata%") sTemp = oWShell.ExpandEnvironmentStrings("%temp%") sAllUsersProfile = oWShell.ExpandEnvironmentStrings("%allusersprofile%") RegReadValue HKLM, "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList", "ProfilesDirectory", sProfilesDirectory, "REG_EXPAND_SZ" If NOT oFso.FolderExists(sProfilesDirectory) Then sProfilesDirectory = oFso.GetParentFolderName(oWShell.ExpandEnvironmentStrings("%userprofile%")) End If sProgramFiles = oWShell.ExpandEnvironmentStrings("%programfiles%") 'sProgramFilesX86 = deferred. Depends on operating system architecture check sCommonProgramFiles = oWShell.ExpandEnvironmentStrings("%commonprogramfiles%") 'sCommonProgramFilesX86 = deferred. Depends on operating system architecture check sProgramData = oWSHell.ExpandEnvironmentStrings("%programdata%") sWinDir = oWShell.ExpandEnvironmentStrings("%windir%") 'sPackageFolder = deferred sWICacheDir = sWinDir & "\" & "Installer" sScrubDir = sTemp & "\" & SCRIPTNAME sScriptDir = wscript.ScriptFullName sScriptDir = Left(sScriptDir, InStrRev(sScriptDir, "\")) ' ensure 64 bit host if needed If InStr(LCase(wscript.path), "syswow64") > 0 Then RelaunchAs64Host ' update result tracking array arrResult(COL_COMPUTERNAME) = oWShell.ExpandEnvironmentStrings("%COMPUTERNAME%") arrResult(COL_DATETIME) = Now arrResult(COL_SCRIPTVERSION) = SCRIPTVERSION ' create the temp folder '----------------------- If Not oFso.FolderExists(sScrubDir) Then oFso.CreateFolder sScrubDir ' set the default logging directory '---------------------------------- sLogDir = sScrubDir ' detect bitness of the operating system '---------------------------------------- arrResult(COL_WINARCHITECTURE) = "x86" arrResult(COL_USERNAME) = oWShell.ExpandEnvironmentStrings("%USERDOMAIN%") & "\" & oWShell.ExpandEnvironmentStrings("%USERNAME%") Set ComputerItem = oWmiLocal.ExecQuery("Select * from Win32_ComputerSystem") For Each Item In ComputerItem f64 = Instr(Left(Item.SystemType, 3), "64") > 0 Next If f64 Then arrResult(COL_WINARCHITECTURE) = "x64" If f64 Then sProgramFilesX86 = oWShell.ExpandEnvironmentStrings("%programfiles(x86)%") If f64 Then sCommonProgramFilesX86 = oWShell.ExpandEnvironmentStrings("%CommonProgramFiles(x86)%") ' update error flag '------------------ SetError ERROR_SCRIPTINIT ' get Win32_OperatingSystem details '---------------------------------- Set ComputerItem = oWmiLocal.ExecQuery("Select * from Win32_OperatingSystem") For Each Item in ComputerItem sOSinfo = sOSinfo & Item.Caption sOSinfo = sOSinfo & Item.OtherTypeDescription sOSinfo = sOSinfo & ", " & "SP " & Item.ServicePackMajorVersion arrResult(COL_WINOS) = Replace(sOSinfo, ",", "") sOSinfo = sOSinfo & ", " & "Version: " & Item.Version sOsVersion = Item.Version arrResult(COL_WINVERSION) = sOSVersion sOSinfo = sOSinfo & ", " & "Codepage: " & Item.CodeSet sOSinfo = sOSinfo & ", " & "Country Code: " & Item.CountryCode sOSinfo = sOSinfo & ", " & "Language: " & Item.OSLanguage Next ' get VersionNT number '--------------------- arrVersion = Split(sOsVersion, Delimiter(sOsVersion)) iVersionNt = CInt(arrVersion(0)) * 100 + CInt(arrVersion(1)) ' ensure sufficient registry permisions '-------------------------------------- fIsElevated = CheckRegPermissions If NOT fIsElevated AND NOT fNoElevate Then ' try to relaunch elevated RelaunchElevated ' can't relaunch. Exit out SetError ERROR_ELEVATION If UCase(Mid(Wscript.FullName, Len(Wscript.Path) + 2, 1)) = "C" Then If Not fLogInitialized Then CreateLog Log "Error: Insufficient registry access permissions - exiting" End If SetRetVal iError wscript.quit iError End If ' clear error flags '------------------ ClearError ERROR_ELEVATION ClearError ERROR_SCRIPTINIT ' ensure CScript as engine '------------------------ If Not UCase(Mid(Wscript.FullName, Len(Wscript.Path) + 2, 1)) = "C" Then RelaunchAsCScript ' set retval for file based logic '-------------------------------- ' value needs to be kept on 'user abort' SetRetVal ERROR_USER_ABORT ' create dictionary objects '-------------------------- Set dicKeepProd = CreateObject("Scripting.Dictionary") Set dicInstalledSku = CreateObject("Scripting.Dictionary") Set dicRemoveSku = CreateObject("Scripting.Dictionary") Set dicKeepSku = CreateObject("Scripting.Dictionary") Set dicKeepLis = CreateObject("Scripting.Dictionary") Set dicKeepFolder = CreateObject("Scripting.Dictionary") Set dicApps = CreateObject("Scripting.Dictionary") Set dicDelRegKey = CreateObject("Scripting.Dictionary") Set dicKeepReg = CreateObject("Scripting.Dictionary") Set dicC2RSuite = CreateObject("Scripting.Dictionary") Set dicDelInUse = CreateObject("Scripting.Dictionary") Set dicDelFolder = CreateObject("Scripting.Dictionary") ' add initial known .exe files that need to be closed '---------------------------------------------------- dicApps.Add "appvshnotify.exe", "appvshnotify.exe" dicApps.Add "integratedoffice.exe", "integratedoffice.exe" dicApps.Add "integrator.exe", "integrator.exe" dicApps.Add "RoamingOffice.exe", "RoamingOffice.exe" dicApps.Add "firstrun.exe", "firstrun.exe" dicApps.Add "setup.exe", "setup.exe" dicApps.Add "communicator.exe", "communicator.exe" dicApps.Add "msosync.exe", "msosync.exe" dicApps.Add "OneNoteM.exe", "OneNoteM.exe" dicApps.Add "iexplore.exe", "iexplore.exe" dicApps.Add "mavinject32.exe", "mavinject32.exe" dicApps.Add "werfault.exe", "werfault.exe" dicApps.Add "perfboost.exe", "perfboost.exe" dicApps.Add "roamingoffice.exe", "roamingoffice.exe" End Sub 'Initialize '------------------------------------------------------------------------------- ' ParseCmdLine ' ' Command line parser '------------------------------------------------------------------------------- Sub ParseCmdLine Dim iCnt, iArgCnt Dim arrArguments Dim sArg0 iArgCnt = Wscript.Arguments.Count If iArgCnt > 0 Then If wscript.Arguments(0) = "UAC" Then If wscript.arguments.count = 1 Then iArgCnt = 0 End If End If If iArgCnt = 0 Then Select Case UCase(wscript.ScriptName) Case Else 'Create the log CreateLog FindInstalledOProducts sDefault = "ALL" arrArguments = Split(Trim(sDefault), " ") If UBound(arrArguments) = -1 Then ReDim arrArguments(0) End Select Else ReDim arrArguments(iArgCnt-1) For iCnt = 0 To (iArgCnt-1) arrArguments(iCnt) = UCase(Wscript.Arguments(iCnt)) Next 'iCnt End If 'iArgCnt = 0 ' hardcode to full removal sArg0 = "ALL" Select Case UCase(sArg0) Case "?" ShowSyntax Case "ALL" fRemoveAll = True fRemoveOse = False Case "C2R" fC2R = True fRemoveAll = False fRemoveOse = False Case Else fRemoveAll = False fRemoveOse = False sSkuRemoveList = sArg0 End Select For iCnt = 0 To UBound(arrArguments) Select Case arrArguments(iCnt) Case "?", "/?", "-?" ShowSyntax Case "/L", "/LOG" fLogInitialized = False If UBound(arrArguments) > iCnt Then If oFso.FolderExists(arrArguments(iCnt + 1)) Then sLogDir = arrArguments(iCnt + 1) Else On Error Resume Next oFso.CreateFolder(arrArguments(iCnt + 1)) If Err <> 0 Then sLogDir = sScrubDir Else sLogDir = arrArguments(iCnt + 1) End If End If Case "/N", "/NOCANCEL" fNoCancel = True Case "/NE", "/NOELEVATE" fNoElevate = True Case "/O", "/OSE" fRemoveOse = True Case "/Q", "/QUIET" fQuiet = True ' for test purposes only! Case "/TR", "/TESTRERUN" fTestRerun = True Case Else End Select Next 'iCnt If Not fLogInitialized Then CreateLog End Sub 'ParseCmdLine '------------------------------------------------------------------------------- ' ShowSyntax ' ' Show the expected syntax for the script usage '------------------------------------------------------------------------------- Sub ShowSyntax Wscript.Echo sErr & vbCrLf & _ SCRIPTFILE & " V " & SCRIPTVERSION & vbCrLf & _ "Copyright (c) Microsoft Corporation. All Rights Reserved" & vbCrLf & vbCrLf & _ SCRIPTFILE & " - Remove " & ONAME & vbCrLf & _ "when a regular uninstall is no longer possible" & vbCrLf & vbCrLf & _ "Usage:" & vbTab & SCRIPTFILE & " C2R" & vbCrLf & vbCrLf & _ vbTab & "/? ' Displays this help"& vbCrLf Wscript.Quit End Sub 'ShowSyntax '------------------------------------------------------------------------------- ' FindInstalledOProducts ' ' Office configuration products are listed with their configuration product ' name in the "Uninstall" key. '------------------------------------------------------------------------------- Sub FindInstalledOProducts Dim ArpItem Dim sCurKey, sValue, sConfigName, sCulture, sDisplayVersion, sUninstallString Dim iLeft, iRight Dim arrKeys Dim fSystemComponent0, fDisplayVersion, fUninstallString If dicInstalledSku.Count > 0 Then Exit Sub 'Already done from command line parser Log "Detecting installed products " & " (" & Time & ")" ' identify C2R products If RegEnumKey(HKLM, REG_ARP, arrKeys) Then ' configuration products ' pre-filter on C2R and .MSI Office products For Each ArpItem in arrKeys sCurKey = REG_ARP & ArpItem & "\" sValue = "" sDisplayVersion = "" fSystemComponent0 = NOT (RegReadValue(HKLM, sCurKey, "SystemComponent", sValue, "REG_DWORD") AND (sValue = "1")) fDisplayVersion = RegReadValue(HKLM, sCurKey, "DisplayVersion", sValue, "REG_SZ") If fDisplayVersion Then sDisplayVersion = sValue If Len(sValue) > 1 Then fDisplayVersion = (Left(sValue,2) = OVERSIONMAJOR) Else fDisplayVersion = False End If End If fUninstallString = RegReadValue(HKLM, sCurKey, "UninstallString", sUninstallString, "REG_SZ") ' filter on C2R configuration SKU If (fSystemComponent0 AND fDisplayVersion AND InStr(UCase(sUninstallString), UCase(OREGREFC2R)) > 0) Then iLeft = InStr(ArpItem, " - ") + 2 iRight = InStr(iLeft, ArpItem, " - ") - 1 If iRight > 0 Then sConfigName = Trim(Mid(ArpItem, iLeft, (iRight - iLeft))) sCulture = Mid(ArpItem, iRight + 3) Else sConfigName = Trim(Left(ArpItem, iLeft - 3)) sCulture = Mid(ArpItem, iLeft) End If sConfigName = Replace(sConfigName, "Microsoft", "") sConfigName = Replace(sConfigName, "Office", "") sConfigName = Replace(sConfigName, "Professional", "Pro") sConfigName = Replace(sConfigName, "Standard", "Std") sConfigName = Replace(sConfigName, "(Technical Preview)", "") sConfigName = Replace(sConfigName, "15", "") sConfigName = Replace(sConfigName, "2013", "") sConfigName = Replace(sConfigName, " ", "") sConfigName = Replace(sConfigName, "Project", "Prj") sConfigName = Replace(sConfigName, "Visio", "Vis") If NOT dicInstalledSku.Exists(ArpItem) Then dicInstalledSku.Add ArpItem, sConfigName & " - " & sDisplayVersion ' categorize the SKU as C2R If NOT dicC2RSuite.Exists(ArpItem) Then dicC2RSuite.Add ArpItem, sConfigName & " - " & sDisplayVersion ElseIf (fSystemComponent0 AND fDisplayVersion AND InStr(UCase(ArpItem), UCase(OREGREF)) > 0) Then ' classic .msi install SKU iLeft = InStr(ArpItem, ".") + 1 iRight = InStr(iLeft, ArpItem, "-") - 1 sConfigName = Mid(ArpItem, iLeft) sCulture = "" If NOT dicKeepSku.Exists(ArpItem) Then dicKeepSku.Add ArpItem, sConfigName & " - " & sDisplayVersion End If ' Other products If InScope(ArpItem) Then Select Case Mid(ArpItem,11,4) Case "007E", "008F", "008C" sConfigName = "Habanero" RegReadValue HKLM, sCurKey, "DisplayName", sConfigName, "REG_SZ" If NOT dicInstalledSku.Exists(ArpItem) Then dicInstalledSku.Add ArpItem, sConfigName & " - " & sDisplayVersion If NOT dicC2RSuite.Exists(ArpItem) Then dicC2RSuite.Add ArpItem, sConfigName & " - " & sDisplayVersion Case "24E1", "237A" sConfigName = "MSOIDLOGIN" If NOT dicInstalledSku.Exists(ArpItem) Then dicInstalledSku.Add ArpItem, sConfigName & " - " & sDisplayVersion If NOT dicC2RSuite.Exists(ArpItem) Then dicC2RSuite.Add ArpItem, sConfigName & " - " & sDisplayVersion Case Else ' not in scope for c2r removal! If NOT dicKeepSku.Exists(ArpItem) Then dicKeepSku.Add ArpItem, ArpItem End Select End If 'InScope Next 'ArpItem End If 'RegEnumKey End Sub 'FindInstalledOProducts '------------------------------------------------------------------------------- ' EnsureValidWIMetadata ' ' Ensures that only valid metadata entries exist to avoid API failures. ' Invalid entries will be removed '------------------------------------------------------------------------------- Sub EnsureValidWIMetadata(hDefKey, sKey, iValidLength) Dim arrKeys Dim SubKey If Len(sKey) > 1 Then If Right(sKey, 1) = "\" Then sKey = Left(sKey, Len(sKey) - 1) End If If RegEnumKey(hDefKey, sKey, arrKeys) Then For Each SubKey in arrKeys If NOT Len(SubKey) = iValidLength Then RegDeleteKey hDefKey, sKey & "\" & SubKey & "\" End If Next 'SubKey End If End Sub 'EnsureValidWIMetadata '------------------------------------------------------------------------------- ' CleanO15SPP ' ' Clean OSPP for Office 2013 '------------------------------------------------------------------------------- Sub CleanO15SPP Dim sCleanO15SPP, sCmd If NOT (dicC2RSuite.Count > 0 OR dicKeepSku.Count > 0) Then Log " - No C2R product registered. Skipping CleanO15SPP" Exit Sub End If sCleanO15SPP = "CleanO15SPPx86.exe" If f64 Then sCleanO15SPP = "CleanO15SPPx64.exe" If oFso.FileExists(sScriptDir & sCleanO15SPP) Then sCmd = sScriptDir & sCleanO15SPP Log " Running: " & sCmd On Error Resume Next sRetVal = oWShell.Run(sCmd, 0, True) Log " Return value: " & sRetVal On Error Goto 0 End If End Sub 'CleanO15SPP '------------------------------------------------------------------------------- ' DelSchtasks ' ' Delete know scheduled tasks. '------------------------------------------------------------------------------- Sub DelSchtasks () Dim sCmd If CBool(iError AND ERROR_USERCANCEL) Then Exit Sub Log "Removing scheduled tasks" & " (" & Time & ")" LogOnly " - FF_INTEGRATEDstreamSchedule" oWShell.Run "SCHTASKS /Delete /TN FF_INTEGRATEDstreamSchedule /F", 0, False wscript.sleep 500 LogOnly " - FF_INTEGRATEDUPDATEDETECTION" oWShell.Run "SCHTASKS /Delete /TN FF_INTEGRATEDUPDATEDETECTION /F", 0, False sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "\Microsoft\Office\FF_INTEGRATEDUPDATEDETECTION" & Chr(34) & " /F" oWShell.Run sCmd, 0, False wscript.sleep 500 LogOnly " - C2RAppVLoggingStart" oWShell.Run "SCHTASKS /Delete /TN C2RAppVLoggingStart /F", 0, False wscript.sleep 500 LogOnly " - Office 15 Subscription Heartbeat" sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "Office 15 Subscription Heartbeat" & Chr(34) & " /F" oWShell.Run sCmd, 0, False sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "\Microsoft\Office\Office 15 Subscription Heartbeat" & Chr(34) & " /F" oWShell.Run sCmd, 0, False wscript.sleep 500 LogOnly " - Microsoft Office 15 Sync Maintenance" sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "Microsoft Office 15 Sync Maintenance for {d068b555-9700-40b8-992c-f866287b06c1}" & Chr(34) & " /F" oWShell.Run sCmd, 0, False wscript.sleep 500 LogOnly " - OfficeInventoryAgentFallBack" sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "\Microsoft\Office\OfficeInventoryAgentFallBack" & Chr(34) & " /F" oWShell.Run sCmd, 0, False wscript.sleep 500 LogOnly " - OfficeInventoryAgentLogOn" sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "\Microsoft\Office\OfficeInventoryAgentLogOn" & Chr(34) & " /F" oWShell.Run sCmd, 0, False 'Added for Beta2 LogOnly " - Office Background Streaming" sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "Office Background Streaming" & Chr(34) & " /F" oWShell.Run sCmd, 0, False wscript.sleep 500 LogOnly " - Office Automatic Updates" sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "\Microsoft\Office\Office Automatic Updates" & Chr(34) & " /F" oWShell.Run sCmd, 0, False wscript.sleep 500 LogOnly " - Office Subscription Maintenance" sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "Office Subscription Maintenance" & Chr(34) & " /F" oWShell.Run sCmd, 0, False wscript.sleep 500 End Sub '------------------------------------------------------------------------------- ' CloseOfficeApps ' ' End all running instances of applications that will be removed. '------------------------------------------------------------------------------- Sub CloseOfficeApps Dim Processes, Process, app, prop Dim sAppName, sOut, sUserWarn Dim fWait Dim iRet On Error Resume Next fWait = False iProcCloseCnt = iProcCloseCnt + 1 If fRerun Then Exit Sub If NOT fUserConsent Then ' detect processes to allow a user warning sUserWarn = "Please save all open documents and close all Office, IE and Windows Explorer applications before proceeding." & vbCrLf & _ "When you click OK this removal process will terminate all running Office, IE and Windows Explorer processes and applications." & vbCrLf & vbCrLf & _ "Click ‘Cancel’ to to end this removal now." For Each app in dicApps.Keys sAppName = Replace(app, ".", "%.") Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process Where Name like '" & sAppName & "'") For Each Process in Processes If NOT InStr(sUserWarn, Process.Name) > 0 Then sUserWarn = sUserWarn & vbCrLf & " - " & Process.Name Next 'Process Next 'app Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process") For Each Process in Processes For Each prop in Process.Properties_ If prop.Name = "ExecutablePath" Then If InStr(UCase(prop.Value), UCase(OREGREFC2R)) > 0 Then If NOT InStr(sUserWarn, Process.Name) > 0 Then sUserWarn = sUserWarn & vbCrLf & " - " & Process.Name End If End If 'ExcecutablePath Next 'prop Next 'Process If (InStr(sUserWarn, " - ") > 0 AND NOT fQuiet) Then iRet = MsgBox(sUserWarn, 49, DLGTITLE) If iRet = 2 Then SetError ERROR_USERCANCEL ExitScript Else fUserConsent = True End If End If End If 'fUserConsent ' end known processes first For Each app in dicApps.Keys sAppName = Replace(app, ".", "%.") Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process Where Name like '" & sAppName & "'") For Each Process in Processes sOut = " - End process '" & Process.Name iRet = Process.Terminate() CheckError "CloseOfficeApps: " & "Process.Name" Log sOut & "' returned: " & iRet fWait = True Next 'Process Next 'app ' end running applications Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process") For Each Process in Processes For Each prop in Process.Properties_ If prop.Name = "ExecutablePath" Then If InStr(UCase(prop.Value), UCase(OREGREFC2R)) > 0 Then sOut = " - End process '" & Process.Name iRet = Process.Terminate() CheckError "CloseOfficeApps: " & "Process.Name" Log sOut & "' returned: " & iRet fWait = True End If End If 'ExcecutablePath Next 'prop Next 'Process If fWait Then wscript.sleep 5000 End Sub 'CloseOfficeApps '------------------------------------------------------------------------------- ' Uninstall ' ' Identify and invoke default uninstall command for a regular uninstall. '------------------------------------------------------------------------------- Sub Uninstall Dim OseService, srvc Dim hDefKey, sSubKeyName, sValue, Name, arrNames, arrTypes Dim sku, prod, sUninstallCmd, sReturn, sMsiProp, sCmd Dim i If CBool(iError AND ERROR_USERCANCEL) Then Exit Sub ' check if OSE service is *installed, *not disabled, *running under System context. Log " - Checking state of OSE service" & " (" & Time & ")" Set OseService = oWmiLocal.Execquery("Select * From Win32_Service Where Name like 'ose%'") For Each srvc in OseService If (srvc.StartMode = "Disabled") AND (Not srvc.ChangeStartMode("Manual") = 0) Then _ Log " - Conflict detected: OSE service is disabled" If (Not srvc.StartName = "LocalSystem") AND (srvc.Change( , , , , , , "LocalSystem", "")) Then _ Log " - Conflict detected: OSE service not running as LocalSystem" Next 'srvc If NOT dicC2RSuite.Count > 0 Then Log " - No uninstallable C2R items registered in Uninstall" End If ' remove the published component registration for C2R packages Log " - Removing published component registration for C2R packages" & " (" & Time & ")" ' delete the manifest files If oFso.FolderExists(sPackageFolder & "\root\Integration") Then sCmd = "cmd.exe /c del " & chr(34) & sPackageFolder & "\root\Integration\C2RManifest*.xml" & chr(34) Log " Running: " & sCmd sReturn = oWShell.Run (sCmd, 0, True) Log " Return value: " & sReturn If oFso.FileExists(sPackageFolder & "\root\Integration\integrator.exe") Then ' Beta2 sCmd = chr(34) & sPackageFolder & "\root\Integration\integrator.exe" & chr(34) & " /U /Extension PackageRoot=" & chr(34) & sPackageFolder & "\root" & chr(34) & " PackageGUID=" & sPackageGuid Log " Running: " & sCmd sReturn = oWShell.Run (sCmd, 0, True) Log " Return value: " & sReturn ' Beta1 sCmd = chr(34) & sPackageFolder & "\root\Integration\integrator.exe" & chr(34) & " /U" Log " Running: " & sCmd sReturn = oWShell.Run (sCmd, 0, True) Log " Return value: " & sReturn End If If oFso.FileExists(sProgramData & "\Microsoft\ClickToRun\{" & sPackageGuid & "}\integrator.exe") Then sCmd = chr(34) & sProgramData & "\Microsoft\ClickToRun\{" & sPackageGuid & "}\integrator.exe" & chr(34) & " /U /Extension PackageRoot=" & chr(34) & sPackageFolder & "\root" & chr(34) & " PackageGUID=" & sPackageGuid Log " Running: " & sCmd sReturn = oWShell.Run (sCmd, 0, True) Log " Return value: " & sReturn End If End If ' delete potential blocking registry keys for msiexec based tasks Log " - Removing C2R and App-V registry data" & " (" & Time & ")" If fC2R Then For Each sku in dicC2RSuite.Keys ' remove the ARP entry RegDeleteKey HKLM, REG_ARP & sku Next 'sku RegDeleteKey HKCU, "SOFTWARE\Microsoft\Office\15.0\ClickToRun" RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\15.0\ClickToRun" ' AppV keys hDefKey = HKCU sSubKeyName = "SOFTWARE\Microsoft\AppV\ISV" Do If RegEnumValues(hDefKey, sSubKeyName, arrNames, arrTypes) Then For Each Name in arrNames If InStr(LCase(Name), LCase(OREGREFC2R)) > 0 Then RegDeleteValue hDefKey, sSubKeyName, Name, False Next 'Name End If 'RegEnumValues If hDefKey = HKLM Then Exit Do hDefKey = HKLM Loop End If ' msiexec based uninstall sMsiProp = " REBOOT=ReallySuppress NOREMOVESPAWN=True" Log " - Detect Msi based products" & " (" & Time & ")" For Each prod in oMsi.Products If CheckDelete(prod) Then Log vbCrLf & "Calling msiexec.exe to remove " & prod & " (" & Time & ")" sUninstallCmd = "msiexec.exe /x" & prod & sMsiProp If fQuiet Then sUninstallCmd = sUninstallCmd & " /q" Else sUninstallCmd = sUninstallCmd & " /qb-!" End If sUninstallCmd = sUninstallCmd & " /l*v " & chr(34) & sLogDir & "\Uninstall_" & prod & ".log" & chr(34) CloseOfficeApps LogOnly " - Calling msiexec with '" & sUninstallCmd & "'" sReturn = oWShell.Run(sUninstallCmd, 0, True) Log " - msiexec returned: " & SetupRetVal(sReturn) & " (" & sReturn & ")" & " (" & Time & ")" fRebootRequired = fRebootRequired OR (sReturn = "3010") If fRebootRequired Then SetError ERROR_REBOOT_REQUIRED Select Case CInt(sReturn) Case ERROR_SUCCESS,ERROR_SUCCESS_CONFIG_COMPLETE,ERROR_SUCCESS_REBOOT_REQUIRED 'success no action required Case Else SetError ERROR_STAGE1 End Select End If 'CheckDelete Next 'Product Log vbCrLf & "Calling MSI based removal utility" Log "=================================" sCmd = "cscript " & chr(34) & sScriptDir & "OffScrub_O15Msi.vbs" & chr(34) & " CLIENTALL /L " & chr(34) & sLogDir & chr(34) & " /qb" sRetVal = oWShell.Run(sCmd, , True) Log " MSI based removal returned: " & sRetVal End Sub 'Uninstall '------------------------------------------------------------------------------- ' RegWipe ' ' Removal of left behind registry data '------------------------------------------------------------------------------- Sub Regwipe Dim hDefKey, item, name, value, RetVal Dim sGuid, sSubKeyName, sValue, sCmd Dim i, iLoopCnt Dim arrKeys, arrNames, arrTypes, arrTestNames, arrTestTypes Dim arrMultiSzValues, arrMultiSzNewValues Dim fDelReg If CBool(iError AND ERROR_USERCANCEL) Then Exit Sub Log "Registry CleanUp" & " (" & Time & ")" CloseOfficeApps ' Note: ARP entries have already been cleared in uninstall stage ' HKCU Registration RegDeleteKey HKCU, "Software\Microsoft\Office\15.0\Registration" ' C2R specifics If fC2R Then ' AppV key "SOFTWARE\Microsoft\AppV" has already been cleared in uninstall stage ' Virtual InstallRoot RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\15.0\Common\InstallRoot\Virtual" ' Mapi 15 reg RegDeleteKey HKLM, "SOFTWARE\Classes\CLSID\{2027FC3B-CF9D-4ec7-A823-38BA308625CC}" ' C2R keys RegDeleteKey HKCU, "SOFTWARE\Microsoft\Office\15.0\ClickToRun" RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\15.0\ClickToRun" RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\15.0\ClickToRunStore" ' Office key in HKLM ClearOfficeHKLM "SOFTWARE\Microsoft\Office\" & OVERSION End If If fC2R OR fRemoveAll Then ' Run key sSubKeyName = "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" If RegEnumValues (HKLM, sSubKeyName, arrNames, arrTypes) Then For Each name in arrNames If RegReadValue(HKLM, sSubKeyName, name, sValue, "REG_SZ") Then If InStr(LCase(sValue), LCase(OREGREFC2R)) > 0 Then RegDeleteValue HKLM, sSubKeyName, name, False End If Next 'item End If RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Run", "Lync15", False ' Protocol Handlers RegDeleteKey HKLM, "SOFTWARE\Classes\Protocols\Handler\osf" ' Groove ShellIconOverlayIdentifiers RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\Microsoft SPFS Icon Overlay 1 (ErrorConflict)" RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\Microsoft SPFS Icon Overlay 2 (SyncInProgress)" RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\Microsoft SPFS Icon Overlay 3 (InSync)" RegDeleteKey HKLM, "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\Microsoft SPFS Icon Overlay 1 (ErrorConflict)" RegDeleteKey HKLM, "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\Microsoft SPFS Icon Overlay 2 (SyncInProgress)" RegDeleteKey HKLM, "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\Microsoft SPFS Icon Overlay 3 (InSync)" ' Shell extensions RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{B28AA736-876B-46DA-B3A8-84C5E30BA492}", False RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{8B02D659-EBBB-43D7-9BBA-52CF22C5B025}", False RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{0875DCB6-C686-4243-9432-ADCCF0B9F2D7}", False RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{42042206-2D85-11D3-8CFF-005004838597}", False RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{993BE281-6695-4BA5-8A2A-7AACBFAAB69E}", False RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{C41662BB-1FA0-4CE0-8DC5-9B7F8279FF97}", False RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{506F4668-F13E-4AA1-BB04-B43203AB3CC0}", False RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{D66DC78C-4F61-447F-942B-3FB6980118CF}", False RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{46137B78-0EC3-426D-8B89-FF7C3A458B5E}", False ' BHO RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{31D09BA0-12F5-4CCE-BE8A-2923E76605DA}" RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{B4F3A835-0E21-4959-BA22-42B3008E02FF}" RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{D0498E0A-45B7-42AE-A9AA-ABA463DBD3BF}" RegDeleteKey HKLM, "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{31D09BA0-12F5-4CCE-BE8A-2923E76605DA}" RegDeleteKey HKLM, "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{B4F3A835-0E21-4959-BA22-42B3008E02FF}" RegDeleteKey HKLM, "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{D0498E0A-45B7-42AE-A9AA-ABA463DBD3BF}" ' OneNote Namespace Extension for Desktop RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Desktop\NameSpace\{0875DCB6-C686-4243-9432-ADCCF0B9F2D7}" ' Web Sites RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Desktop\Namespace\{B28AA736-876B-46DA-B3A8-84C5E30BA492}" RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\NetworkNeighborhood\Namespace\{46137B78-0EC3-426D-8B89-FF7C3A458B5E}" ' VolumeCaches RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Microsoft Office Temp Files" End If ' ARP ' Note: configuration entries have already been removed ' as part of the 'Uninstall' stage If RegEnumKey(HKLM, REG_ARP, arrKeys) Then For Each item in arrKeys If Len(item) > 37 Then sGuid = UCase(Left(item, 38)) If CheckDelete(sGuid) Then RegDeleteKey HKLM, REG_ARP & item & "\" End If 'Len(Item)>37 Next 'Item End If ' UpgradeCodes, WI config, WI global config Log " - Scanning Windows Installer metadata for removeable UpgradeCodes" & " (" & Time & ")" For iLoopCnt = 1 to 5 Select Case iLoopCnt Case 1 sSubKeyName = "SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes\" hDefKey = HKLM Case 2 sSubKeyName = "Installer\UpgradeCodes\" hDefKey = HKCR Case 3 sSubKeyName = "SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\" hDefKey = HKLM Case 4 sSubKeyName = "Installer\Features\" hDefKey = HKCR Case 5 sSubKeyName = "Installer\Products\" hDefKey = HKCR End Select If RegEnumKey(hDefKey, sSubKeyName, arrKeys) Then For Each item in arrKeys ' ensure the expected length for a compressed GUID If Len(item) = 32 Then ' expand the GUID sGuid = GetExpandedGuid(item) ' check if it's an Office key If CheckDelete(sGuid) Then If iLoopCnt < 3 Then ' enum all entries RegEnumValues hDefKey, sSubKeyName & item, arrNames, arrTypes If IsArray(arrNames) Then ' delete entries within removal scope For Each name in arrNames If Len(name) = 32 Then sGuid = GetExpandedGuid(name) If CheckDelete(sGuid) Then RegDeleteValue hDefKey, sSubKeyName & item & "\", name, True Else ' invalid data -> delete the value RegDeleteValue hDefKey, sSubKeyName & item & "\", name, True End If Next 'Name End If 'IsArray(arrNames) ' if all entries were removed - delete the key If NOT RegEnumValues(hDefKey, sSubKeyName & item, arrNames, arrTypes) Then RegDeleteKey hDefKey, sSubKeyName & item & "\" Else 'iLoopCnt >= 3 RegDeleteKey hDefKey, sSubKeyName & item & "\" End If 'iLoopCnt < 3 End If 'InScope End If 'Len(Item)=32 Next 'Item End If 'RegEnumKey Next 'iLoopCnt ' Components in Global Log " - Scanning Windows Installer Global Components metadata" & " (" & Time & ")" sSubKeyName = "SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\" hDefKey = HKLM If RegEnumKey(hDefKey, sSubKeyName, arrKeys) Then For Each item in arrKeys ' ensure the expected length for a compressed GUID If Len(Item) = 32 Then If RegEnumValues(hDefKey, sSubKeyName & item, arrNames, arrTypes) Then For Each name in arrNames If Len(Name) = 32 Then sGuid = GetExpandedGuid(Name) If CheckDelete(sGuid) Then RegDeleteValue hDefKey, sSubKeyName & item & "\", name, False ' if all entries were removed - delete the key If NOT RegEnumValues(hDefKey, sSubKeyName & item, arrTestNames, arrTestTypes) Then RegDeleteKey hDefKey, sSubKeyName & item & "\" End If End If '32 Next 'Name End If 'RegEnumValues End If '32 Next 'Item End If 'RegEnumKey ' Published Components Log " - Scanning Windows Installer Published Components metadata" & " (" & Time & ")" sSubKeyName = "Installer\Components\" hDefKey = HKCR If RegEnumKey(hDefKey, sSubKeyName, arrKeys) Then For Each item in arrKeys ' ensure the expected length for a compressed GUID If Len(Item) = 32 Then If RegEnumValues(hDefKey, sSubKeyName & item, arrNames, arrTypes) Then For Each name in arrNames If RegReadValue (hDefKey, sSubKeyName & item, name, sValue, "REG_MULTI_SZ") Then arrMultiSzValues = Split(sValue, chr(13)) If IsArray(arrMultiSzValues) Then i = -1 ReDim arrMultiSzNewValues(-1) fDelReg = False For Each value in arrMultiSzValues If Len(value) > 19 Then sGuid = "" If GetDecodedGuid(Left(value, SQUISHED), sGuid) Then If CheckDelete(sGuid) Then fDelReg = True Else i = i + 1 ReDim Preserve arrMultiSzNewValues(i) arrMultiSzNewValues(i) = value End If 'CheckDelete End If 'decode End If '19 Next 'Value If NOT (i = -1) Then If NOT UBound(arrMultiSzValues) = i Then oReg.SetMultiStringValue hDefKey, sSubKeyName & item, name,arrMultiSzNewValues Else If fDelReg Then RegDeleteValue hDefKey, sSubKeyName & item & "\", name, True ' if all entries were removed - delete the key If NOT RegEnumValues(hDefKey, sSubKeyName & item, arrTestNames, arrTestTypes) Then RegDeleteKey hDefKey, sSubKeyName & item & "\" End If 'DelReg End If End If 'IsArray End If Next 'Name End If 'RegEnumValues End If '32 Next 'Item End If 'RegEnumKey End Sub 'Regwipe '------------------------------------------------------------------------------- ' FileWipe ' ' Removal of left behind services, files and shortcuts '------------------------------------------------------------------------------- Sub FileWipe Dim scRoot If CBool(iError AND ERROR_USERCANCEL) Then Exit Sub Log vbCrLf & "File Cleanup" & " (" & Time & ")" CloseOfficeApps DelSchtasks ' remove the OfficeSvc service Log " - Deleting OfficeSvc service" & " (" & Time & ")" DeleteService "OfficeSvc" ' adding additional processes for termination dicApps.Add "explorer.exe", "explorer.exe" dicApps.Add "msiexec.exe", "msiexec.exe" dicApps.Add "ose.exe", "ose.exe" ' delete C2R package files If fC2R Then Log " - Deleting C2R package files" & " (" & Time & ")" If oFso.FolderExists(sProgramFiles & "\Microsoft Office 15") Then Log " Attention: Now closing Explorer.exe for file delete operations" Log " Explorer will automatically restart." wscript.sleep 2000 CloseOfficeApps End If Log " - Deleting Office folders" & " (" & Time & ")" DeleteFolder sProgramFiles & "\Microsoft Office 15" If f64 Then DeleteFolder sCommonProgramFilesX86 & "\Microsoft Office 15" DeleteFolder sProgramData & "\Microsoft\ClickToRun" DeleteFolder sProgramData & "\Microsoft\office\FFPackageLocker" ' Added with Beta2 If oFso.FileExists(sProgramData & "\Microsoft\office\FFPackageLocker") Then DeleteFile sProgramData & "\Microsoft\office\FFPackageLocker" If oFso.FileExists(sProgramData & "\Microsoft\office\FFStatePBLocker") Then DeleteFile sProgramData & "\Microsoft\office\FFStatePBLocker" DeleteFolder sProgramData & "\Microsoft\office\Heartbeat" DeleteFolder oWShell.ExpandEnvironmentStrings("%userprofile%") & "\Microsoft Office" DeleteFolder oWShell.ExpandEnvironmentStrings("%userprofile%") & "\Microsoft Office 15" End If ' restore explorer.exe if needed RestoreExplorer ' delete shortcuts Log " - Search and delete shortcuts" & " (" & Time & ")" CleanShortcuts sAllUsersProfile, True, False CleanShortcuts sProfilesDirectory, True, False ' delete empty folder structures If dicDelFolder.Count > 0 Then Log " - Removing empty folders" DeleteEmptyFolders End If ' add the collected files in use for delete on reboot If dicDelInUse.Count > 0 Then ScheduleDeleteEx Log "File Cleanup complete" & " (" & Time & ")" End Sub ' FileWipe '------------------------------------------------------------------------------- ' CleanShortcuts ' ' Recursively search all profile folders for Office shortcuts in scope '------------------------------------------------------------------------------- Sub CleanShortcuts (sFolder, fDelete, fUnPin) Dim oFolder, fld, file, sc Set oFolder = oFso.GetFolder(sFolder) ' exclude system protected link folders If CBool(oFolder.Attributes AND 1024) Then Exit Sub On Error Resume Next For Each fld In oFolder.SubFolders If Err <> 0 Then CheckError "CleanShortcuts: " & vbTab & sFolder Else CleanShortcuts fld.Path, fDelete, fUnPin End If Next For Each file In oFolder.Files If LCase(Right(file.Path, 4)) = ".lnk" Then set sc = oWShell.CreateShortcut(file.Path) ' C2R shortcuts If InStr(sc.TargetPath, sPackageFolder) > 0 Then If fUnPin Then UnPin file If fDelete Then DeleteFile file.Path End If End If Next On Error Goto 0 End Sub 'CleanShortcuts '------------------------------------------------------------------------------- ' UnPin ' ' Unpins a shortcut from the taskbar or start menu '------------------------------------------------------------------------------- Sub UnPin(file) Dim fldItem, verb On Error Resume Next Set fldItem = oShellApp.NameSpace(file.ParentFolder.Path).ParseName(file.Name) For Each verb in fldItem.Verbs Select Case Replace(verb, "&", "") Case "Unpin from Taskbar", "Von Taskleiste lösen", "Détacher du barre des tâches", "Détacher de la barre des tâches", "Desanclar de la barra de tareas", "Ta bort från Aktivitetsfältet", "タスク バーに表示しない(K)", "작업 표시줄에서 제거(K)", "Открепить от панели задач" verb.DoIt Case "Unpin from Start Menu", "Vom Startmenü lösen", "Détacher du menu Démarrer", "Détacher de la menu Démarrer" If iVersionNT = 601 Then verb.DoIt End Select Next On Error Goto 0 End Sub '------------------------------------------------------------------------------- ' ClearOfficeHKLM ' ' Recursively search and clear the HKLM Office key from references in scope '------------------------------------------------------------------------------- Sub ClearOfficeHKLM (sSubKeyName) Dim key, name Dim sValue Dim arrKeys, arrNames, arrTypes Dim arrTestNames, arrTestTypes, arrTestKeys ' recursion If RegEnumKey(HKLM, sSubKeyName, arrKeys) Then For Each key in arrKeys ClearOfficeHKLM sSubKeyName & "\" & key Next 'key End If ' identify & clear removable entries If RegEnumValues(HKLM, sSubKeyName, arrNames, arrTypes) Then For Each name in arrNames If RegReadValue(HKLM, sSubKeyName, name, sValue, "REG_SZ") Then If InStr(LCase(sValue), LCase(OREGREFC2R)) > 0 Then RegDeleteValue HKLM, sSubKeyName, name, False End If Next 'item End If ' clear out empty keys If (NOT RegEnumValues(HKLM, sSubKeyName, arrNames, arrTypes)) AND _ (NOT RegEnumKey(HKLM, sSubKeyName, arrKeys)) Then _ RegDeleteKey HKLM, sSubKeyName End Sub '------------------------------------------------------------------------------- ' ' Helper Functions ' '------------------------------------------------------------------------------- '------------------------------------------------------------------------------- ' CheckRegPermissions ' ' Test the permissions on some key registry locations to determine if ' sufficient permissions are given. '------------------------------------------------------------------------------- Function CheckRegPermissions Const KEY_QUERY_VALUE = &H0001 Const KEY_SET_VALUE = &H0002 Const KEY_CREATE_SUB_KEY = &H0004 Const DELETE = &H00010000 Dim sSubKeyName Dim fReturn CheckRegPermissions = True sSubKeyName = "Software\Microsoft\Windows\" oReg.CheckAccess HKLM, sSubKeyName, KEY_QUERY_VALUE, fReturn If Not fReturn Then CheckRegPermissions = False oReg.CheckAccess HKLM, sSubKeyName, KEY_SET_VALUE, fReturn If Not fReturn Then CheckRegPermissions = False oReg.CheckAccess HKLM, sSubKeyName, KEY_CREATE_SUB_KEY, fReturn If Not fReturn Then CheckRegPermissions = False oReg.CheckAccess HKLM, sSubKeyName, DELETE, fReturn If Not fReturn Then CheckRegPermissions = False End Function 'CheckRegPermissions '------------------------------------------------------------------------------- ' GetMyProcessId ' ' Returns the process id of the own process '------------------------------------------------------------------------------- Function GetMyProcessId() Dim iParentProcessId iParentProcessId = 0 ' try to obtain from creating a new cscript instance On Error Resume Next iParentProcessId = GetObject("winmgmts:root\cimv2").Get("Win32_Process.Handle='" & oWShell.Exec("cscript.exe").ProcessId & "'").ParentProcessId On Error Goto 0 If iParentProcessId > 0 Then ' succeeded to obtain the process id GetMyProcessId = iParentProcessId Exit Function End If ' failed to obtain the id from the creation of a new instance ' get it from enum of Win32_Process Dim Process, Processes Err.Clear Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process WHERE Name='cscript.exe' AND CommandLine like '%" & SCRIPTNAME & "%'") For Each Process in Processes iParentProcessId = Process.ProcessId Exit For Next GetMyProcessId = iParentProcessId End Function 'GetMyProcessId '------------------------------------------------------------------------------- ' Delimiter ' ' Returns the delimiter for a passed in string '------------------------------------------------------------------------------- Function Delimiter (sVersion) Dim iCnt, iAsc Delimiter = " " For iCnt = 1 To Len(sVersion) iAsc = Asc(Mid(sVersion, iCnt, 1)) If Not (iASC >= 48 And iASC <= 57) Then Delimiter = Mid(sVersion, iCnt, 1) Exit Function End If Next 'iCnt End Function '------------------------------------------------------------------------------- ' GetExpandedGuid ' ' Returns the expanded string from a compressed GUID '------------------------------------------------------------------------------- Function GetExpandedGuid (sGuid) Dim i 'Ensure valid length If NOT Len(sGuid) = 32 Then Exit Function GetExpandedGuid = "{" & StrReverse(Mid(sGuid,1,8)) & "-" & _ StrReverse(Mid(sGuid,9,4)) & "-" & _ StrReverse(Mid(sGuid,13,4))& "-" For i = 17 To 20 If i Mod 2 Then GetExpandedGuid = GetExpandedGuid & mid(sGuid,(i + 1),1) Else GetExpandedGuid = GetExpandedGuid & mid(sGuid,(i - 1),1) End If Next GetExpandedGuid = GetExpandedGuid & "-" For i = 21 To 32 If i Mod 2 Then GetExpandedGuid = GetExpandedGuid & mid(sGuid,(i + 1),1) Else GetExpandedGuid = GetExpandedGuid & mid(sGuid,(i - 1),1) End If Next GetExpandedGuid = GetExpandedGuid & "}" End Function 'GetExpandedGuid '------------------------------------------------------------------------------- ' GetCompressedGuid ' ' Returns the compressed string for a GUID '------------------------------------------------------------------------------- Function GetCompressedGuid (sGuid) Dim sCompGUID Dim i 'Ensure Valid Length If NOT Len(sGuid) = 38 Then Exit Function sCompGUID = StrReverse(Mid(sGuid,2,8)) & _ StrReverse(Mid(sGuid,11,4)) & _ StrReverse(Mid(sGuid,16,4)) For i = 21 To 24 If i Mod 2 Then sCompGUID = sCompGUID & Mid(sGuid, (i + 1), 1) Else sCompGUID = sCompGUID & Mid(sGuid, (i - 1), 1) End If Next For i = 26 To 37 If i Mod 2 Then sCompGUID = sCompGUID & Mid(sGuid, (i - 1), 1) Else sCompGUID = sCompGUID & Mid(sGuid, (i + 1), 1) End If Next GetCompressedGuid = sCompGUID End Function '------------------------------------------------------------------------------- ' GetDecodedGuid ' ' Returns the GUID from a squished format '------------------------------------------------------------------------------- Function GetDecodedGuid(sEncGuid, sGuid) Dim sDecode, sTable, sHex, iChr Dim arrTable Dim i, iAsc, pow85, decChar Dim lTotal Dim fFailed fFailed = False sTable = "0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff," & _ "0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff," & _ "0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff," & _ "0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17," & _ "0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27," & _ "0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36," & _ "0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46," & _ "0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff" arrTable = Split(sTable,",") lTotal = 0 : pow85 = 1 For i = 0 To 19 fFailed = True If i Mod 5 = 0 Then lTotal = 0 : pow85 = 1 End If ' i Mod 5 = 0 iAsc = Asc(Mid(sEncGuid,i+1,1)) sHex = arrTable(iAsc) If iAsc >=128 Then Exit For If sHex = "0xff" Then Exit For iChr = CInt("&h"&Right(sHex,2)) lTotal = lTotal + (iChr * pow85) If i Mod 5 = 4 Then sDecode = sDecode & DecToHex(lTotal) pow85 = pow85 * 85 fFailed = False Next 'i If NOT fFailed Then sGuid = "{"&Mid(sDecode,1,8)&"-"& _ Mid(sDecode,13,4)&"-"& _ Mid(sDecode,9,4)&"-"& _ Mid(sDecode,23,2) & Mid(sDecode,21,2)&"-"& _ Mid(sDecode,19,2) & Mid(sDecode,17,2) & Mid(sDecode,31,2) & Mid(sDecode,29,2) & Mid(sDecode,27,2) & Mid(sDecode,25,2) &"}" GetDecodedGuid = NOT fFailed End Function 'GetDecodedGuid '------------------------------------------------------------------------------- ' DecToHex ' ' Convert a long decimal to hex '------------------------------------------------------------------------------- Function DecToHex(lDec) Dim sHex Dim iLen Dim lVal, lExp Dim arrChr arrChr = Array("0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F") sHex = "" lVal = lDec lExp = 16^10 While lExp >= 1 If lVal >= lExp Then sHex = sHex & arrChr(Int(lVal / lExp)) lVal = lVal - lExp * Int(lVal / lExp) Else sHex = sHex & "0" If sHex = "0" Then sHex = "" End If lExp = lExp / 16 Wend iLen = 8 - Len(sHex) If iLen > 0 Then sHex = String(iLen, "0") & sHex DecToHex = sHex End Function '------------------------------------------------------------------------------- ' RelaunchAs64Host ' ' Relaunch self with 64 bit WScript host '------------------------------------------------------------------------------- Sub RelaunchAs64Host Dim Argument, sCmd sCmd = Replace(LCase(wscript.Path), "syswow64", "sysnative") & "\wscript.exe " & Chr(34) & WScript.scriptFullName & Chr(34) If Wscript.Arguments.Count > 0 Then For Each Argument in Wscript.Arguments sCmd = sCmd & " " & chr(34) & Argument & chr(34) Next 'Argument End If Wscript.Quit CLng(oWShell.Run(sCmd, 1, True)) End Sub 'RelaunchAs64Host '------------------------------------------------------------------------------- ' RelaunchElevated ' ' Relaunch the script with elevated permissions '------------------------------------------------------------------------------- Sub RelaunchElevated Dim Argument, Process, Processes Dim iParentProcessId, iSpawnedProcessId Dim sCmdLine, sRetValFile, sValue Dim oShell SetError ERROR_RELAUNCH ' Shell object for relaunch Set oShell = CreateObject("Shell.Application") ' build command line for relaunch sCmdLine = Chr(34) & WScript.ScriptFullName & Chr(34) If Wscript.Arguments.Count > 0 Then For Each Argument in Wscript.Arguments Select Case UCase(Argument) Case "/Q","/QUIET" 'Don't try to relaunch in quiet mode Exit Sub SetError ERROR_ELEVATION_FAILED Case "UAC" 'Already tried elevated relaunch SetError ERROR_ELEVATION_FAILED Exit Sub Case Else sCmdLine = sCmdLine & " " & chr(34) & Argument & chr(34) End Select Next 'Argument End If ' prep work to get the return value from the elevated process iParentProcessId = GetMyProcessId ' ' make user aware of elevation attempt after reboot ' If RegReadValue(HKCU, "SOFTWARE\Microsoft\Office\15.0\CleanC2R", "Rerun", sValue, "REG_DWORD") Then ' oWShell.Popup "System reboot complete. OffScrub will now prompt for elevation!", 10, SCRIPTNAME & " - NOTE!" ' End If ' launch the elevated instance oShell.ShellExecute "cscript.exe", sCmdLine & " /NoElevate UAC", "", "runas", 1 ' get the process id of the spawned instance WScript.Sleep 500 Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process WHERE ParentProcessId='" & iParentProcessId & "'") If Processes.Count > 0 Then For Each Process in Processes iSpawnedProcessId = Process.ProcessId Exit For Next 'Process ' monitor the tasklist to detect the end of the spawned process While oWmiLocal.ExecQuery("Select * From Win32_Process WHERE ProcessId='" & iSpawnedProcessId & "'").Count > 0 WScript.Sleep 3000 Wend ' get the return value from the file Wscript.Quit GetRetValFromFile End If ' elevation failed (user declined) SetError ERROR_ELEVATION_USERDECLINED End Sub 'RelaunchElevated '------------------------------------------------------------------------------- ' RelaunchAsCScript ' ' Relaunch self with Cscript as host '------------------------------------------------------------------------------- Sub RelaunchAsCScript Dim Argument Dim sCmdLine SetError ERROR_RELAUNCH sCmdLine = "cmd.exe /k " & WScript.Path & "\cscript.exe //NOLOGO " & Chr(34) & WScript.scriptFullName & Chr(34) If Wscript.Arguments.Count > 0 Then For Each Argument in Wscript.Arguments sCmdLine = sCmdLine & " " & chr(34) & Argument & chr(34) Next 'Argument End If Wscript.Quit CLng(oWShell.Run(sCmdLine, 1, True)) End Sub 'RelaunchAsCScript '------------------------------------------------------------------------------- ' SetError ' ' Set error bit(s) '------------------------------------------------------------------------------- Sub SetError(ErrorBit) iError = iError OR ErrorBit Select Case ErrorBit Case ERROR_DCAF_FAILURE, ERROR_STAGE2, ERROR_ELEVATION_USERDECLINED, ERROR_ELEVATION, ERROR_SCRIPTINIT iError = iError OR ERROR_FAIL End Select End Sub '------------------------------------------------------------------------------- ' ClearError ' ' Unset error bit(s) '------------------------------------------------------------------------------- Sub ClearError(ErrorBit) iError = iError AND (ERROR_ALL - ErrorBit) Select Case ErrorBit Case ERROR_ELEVATION_USERDECLINED, ERROR_ELEVATION, ERROR_SCRIPTINIT iError = iError AND (ERROR_ALL - ERROR_FAIL) End Select End Sub '------------------------------------------------------------------------------- ' SetRetVal ' ' Write return value to file '------------------------------------------------------------------------------- Sub SetRetVal(iError) Dim RetValFileStream 'don't fail script execution if writing the return value to file fails On Error Resume Next Set RetValFileStream = oFso.createTextFile(sScrubDir & "\" & RETVALFILE, True, True) RetValFileStream.Write iError RetValFileStream.Close On Error Goto 0 End Sub 'SetRetVal '------------------------------------------------------------------------------- ' GetRetValFromFile ' ' Read return value from file. ' Used to ensure return value can get obtained from an elevated process '------------------------------------------------------------------------------- Function GetRetValFromFile () Dim RetValFileStream Dim iRetValFromFile On Error Resume Next 'don't fail script execution when getting the return value from file fails If oFso.FileExists(sScrubDir & "\" & RETVALFILE) Then Set RetValFileStream = oFso.OpenTextFile(sScrubDir & "\" & RETVALFILE, 1, False, -2) GetRetValFromFile = RetValFileStream.ReadAll RetValFileStream.Close Exit Function End If Err.Clear On Error Goto 0 GetRetValFromFile = ERROR_UNKNOWN End Function 'GetRetValFromFile '------------------------------------------------------------------------------- ' GetMyProcessId ' ' Returns the process id of self '------------------------------------------------------------------------------- Function GetMyProcessId() Dim iParentProcessId iParentProcessId = 0 ' try to obtain id from a new child cscript instance ' error handled by fallback to use of Win32_Process On Error Resume Next iParentProcessId = GetObject("winmgmts:root\cimv2").Get("Win32_Process.Handle='" & oWShell.Exec("cscript.exe").ProcessId & "'").ParentProcessId On Error Goto 0 If iParentProcessId > 0 Then ' succeeded to obtain the process id GetMyProcessId = iParentProcessId Exit Function End If ' failed to obtain the id from the creation of a new instance ' get it from enum of Win32_Process Dim Process,Processes Err.Clear Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process WHERE Name='cscript.exe' AND CommandLine like '%" & SCRIPTNAME & "%'") For Each Process in Processes iParentProcessId = Process.ProcessId Exit For Next GetMyProcessId = iParentProcessId End Function 'GetMyProcessId '------------------------------------------------------------------------------- ' CreateLog ' ' Create the removal log file '------------------------------------------------------------------------------- Sub CreateLog Dim DateTime Dim sLogName On Error Resume Next ' create the log file Set DateTime = CreateObject("WbemScripting.SWbemDateTime") DateTime.SetVarDate Now, True sLogName = sLogDir & "\" & oWShell.ExpandEnvironmentStrings("%COMPUTERNAME%") sLogName = sLogName & "_" & Left(DateTime.Value, 14) sLogName = sLogName & "_ScrubLog.txt" Err.Clear Set LogStream = oFso.CreateTextFile(sLogName, True, True) If Err <> 0 Then Err.Clear sLogDir = sScrubDir sLogName = sLogDir & "\" & oWShell.ExpandEnvironmentStrings("%COMPUTERNAME%") sLogName = sLogName & "_" & Left(DateTime.Value, 14) sLogName = sLogName & "_ScrubLog.txt" Set LogStream = oFso.CreateTextFile(sLogName, True, True) End If On Error Goto 0 Log "Microsoft Customer Support Services - " & ONAME & " Removal Utility" & vbCrLf &_ "Removes "& ONAME & " when a regular uninstall is no longer possible." & vbCrLf & vbCrLf & _ "Version: " & vbTab & SCRIPTVERSION & vbCrLf & _ "64 bit OS: " & vbTab & f64 & vbCrLf & _ "Removal start: " & vbTab & Time & vbCrLf fLogInitialized = True End Sub 'CreateLog '------------------------------------------------------------------------------- ' HiveString ' ' Translates the numeric constant into the human readable registry hive string '------------------------------------------------------------------------------- Function HiveString(hDefKey) Select Case hDefKey Case HKCR : HiveString = "HKEY_CLASSES_ROOT" Case HKCU : HiveString = "HKEY_CURRENT_USER" Case HKLM : HiveString = "HKEY_LOCAL_MACHINE" Case HKU : HiveString = "HKEY_USERS" Case Else : HiveString = hDefKey End Select End Function '------------------------------------------------------------------------------- ' RegKeyExists ' ' Returns a boolean for the test on existence of a given registry key '------------------------------------------------------------------------------- Function RegKeyExists(hDefKey, sSubKeyName) Dim arrKeys RegKeyExists = False If oReg.EnumKey(hDefKey, sSubKeyName, arrKeys) = 0 Then RegKeyExists = True End Function '------------------------------------------------------------------------------- ' RegValExists ' ' Returns a boolean for the test on existence of a given registry value '------------------------------------------------------------------------------- Function RegValExists(hDefKey,sSubKeyName,sName) Dim arrValueTypes, arrValueNames Dim i RegValExists = False If Not RegKeyExists(hDefKey,sSubKeyName) Then Exit Function If oReg.EnumValues(hDefKey,sSubKeyName,arrValueNames,arrValueTypes) = 0 AND IsArray(arrValueNames) Then For i = 0 To UBound(arrValueNames) If LCase(arrValueNames(i)) = Trim(LCase(sName)) Then RegValExists = True Next End If 'oReg.EnumValues End Function '------------------------------------------------------------------------------- ' RegReadValue ' ' Read the value of a given registry entry ' The correct type has to be passed in as argument '------------------------------------------------------------------------------- Function RegReadValue(hDefKey, sSubKeyName, sName, sValue, sType) Dim RetVal Dim Item Dim arrValues Select Case UCase(sType) Case "1", "REG_SZ" RetVal = oReg.GetStringValue(hDefKey, sSubKeyName, sName, sValue) If Not RetVal = 0 AND f64 Then RetVal = oReg.GetStringValue(hDefKey, Wow64Key(hDefKey, sSubKeyName), sName, sValue) Case "2", "REG_EXPAND_SZ" RetVal = oReg.GetExpandedStringValue(hDefKey, sSubKeyName, sName, sValue) If NOT RetVal = 0 AND f64 Then RetVal = oReg.GetExpandedStringValue(hDefKey, Wow64Key(hDefKey, sSubKeyName), sName, sValue) Case "3", "REG_BINARY" RetVal = oReg.GetBinaryValue(hDefKey, sSubKeyName, sName, sValue) If NOT RetVal = 0 AND f64 Then RetVal = oReg.GetBinaryValue(hDefKey, Wow64Key(hDefKey, sSubKeyName), sName, sValue) Case "4", "REG_DWORD" RetVal = oReg.GetDWORDValue(hDefKey, sSubKeyName, sName, sValue) If NOT RetVal = 0 AND f64 Then RetVal = oReg.GetDWORDValue(hDefKey, Wow64Key(hDefKey, sSubKeyName), sName, sValue) Case "7", "REG_MULTI_SZ" RetVal = oReg.GetMultiStringValue(hDefKey, sSubKeyName, sName, arrValues) If NOT RetVal = 0 AND f64 Then RetVal = oReg.GetMultiStringValue(hDefKey, Wow64Key(hDefKey, sSubKeyName), sName, arrValues) If RetVal = 0 Then sValue = Join(arrValues, chr(13)) Case Else RetVal = -1 End Select 'sValue RegReadValue = (RetVal = 0) End Function 'RegReadValue '------------------------------------------------------------------------------- ' RegEnumValues ' ' Enumerate a registry key to return all values '------------------------------------------------------------------------------- Function RegEnumValues(hDefKey, sSubKeyName, arrNames, arrTypes) Dim RetVal, RetVal64 Dim arrNames32, arrNames64, arrTypes32, arrTypes64 If f64 Then RetVal = oReg.EnumValues(hDefKey, sSubKeyName, arrNames32, arrTypes32) RetVal64 = oReg.EnumValues(hDefKey, Wow64Key(hDefKey, sSubKeyName), arrNames64, arrTypes64) If (RetVal = 0) AND (NOT RetVal64 = 0) AND IsArray(arrNames32) AND IsArray(arrTypes32) Then arrNames = arrNames32 arrTypes = arrTypes32 End If If (NOT RetVal = 0) AND (RetVal64 = 0) AND IsArray(arrNames64) AND IsArray(arrTypes64) Then arrNames = arrNames64 arrTypes = arrTypes64 End If If (RetVal = 0) AND (RetVal64 = 0) AND IsArray(arrNames32) AND IsArray(arrNames64) AND IsArray(arrTypes32) AND IsArray(arrTypes64) Then arrNames = RemoveDuplicates(Split((Join(arrNames32, "\") & "\" & Join(arrNames64, "\")), "\")) arrTypes = RemoveDuplicates(Split((Join(arrTypes32, "\") & "\" & Join(arrTypes64, "\")), "\")) End If Else RetVal = oReg.EnumValues(hDefKey, sSubKeyName, arrNames, arrTypes) End If 'f64 RegEnumValues = ((RetVal = 0) OR (RetVal64 = 0)) AND IsArray(arrNames) AND IsArray(arrTypes) End Function 'RegEnumValues '------------------------------------------------------------------------------- ' RegEnumKey ' ' Enumerate a registry key to return all subkeys '------------------------------------------------------------------------------- Function RegEnumKey(hDefKey, sSubKeyName, arrKeys) Dim RetVal, RetVal64 Dim arrKeys32, arrKeys64 If f64 Then RetVal = oReg.EnumKey(hDefKey, sSubKeyName, arrKeys32) RetVal64 = oReg.EnumKey(hDefKey, Wow64Key(hDefKey, sSubKeyName), arrKeys64) If (RetVal = 0) AND (NOT RetVal64 = 0) AND IsArray(arrKeys32) Then arrKeys = arrKeys32 If (Not RetVal = 0) AND (RetVal64 = 0) AND IsArray(arrKeys64) Then arrKeys = arrKeys64 If (RetVal = 0) AND (RetVal64 = 0) Then If IsArray(arrKeys32) AND IsArray (arrKeys64) Then arrKeys = RemoveDuplicates(Split((Join(arrKeys32, "\") & "\" & Join(arrKeys64, "\")), "\")) ElseIf IsArray(arrKeys64) Then arrKeys = arrKeys64 Else arrKeys = arrKeys32 End If End If Else RetVal = oReg.EnumKey(hDefKey, sSubKeyName, arrKeys) End If 'f64 RegEnumKey = ((RetVal = 0) OR (RetVal64 = 0)) AND IsArray(arrKeys) End Function 'RegEnumKey '------------------------------------------------------------------------------- ' RegDeleteValue ' ' Wrapper around oReg.DeleteValue to handle 64 bit '------------------------------------------------------------------------------- Sub RegDeleteValue(hDefKey, sSubKeyName, sName, fRegMultiSZ) Dim sDelKeyName, sValue Dim iRetVal Dim fKeep ' ensure trailing "\" sSubKeyName = sSubKeyName & "\" While InStr(sSubKeyName, "\\") > 0 sSubKeyName = Replace(sSubKeyName, "\\", "\") Wend fKeep = dicKeepReg.Exists(LCase(sSubKeyName & sName)) If (NOT fKeep AND f64) Then fKeep = dicKeepReg.Exists(LCase(Wow64Key(hDefKey, sSubKeyName) & sName)) If fKeep Then LogOnly " - Disallowing the delete of still required keypath element: " & HiveString(hDefKey) & "\" & sSubKeyName & sName If NOT fForce Then Exit Sub End If ' check on forced delete If fKeep Then LogOnly " - Enforced delete of still required keypath element: " & HiveString(hDefKey) & "\" & sSubKeyName & sName LogOnly " Remaining applications will need a repair!" End If ' ensure value exists If RegValExists(hDefKey, sSubKeyName, sName) Then sDelKeyName = sSubKeyName ElseIf RegValExists(hDefKey, Wow64Key(hDefKey, sSubKeyName), sName) Then sDelKeyName = Wow64Key(hDefKey, sSubKeyName) Else LogOnly " - Value not found. Cannot delete value: " & HiveString(hDefKey) & "\" & sSubKeyName & sName Exit Sub End If ' prevent unintentional, unsafe REG_MULTI_SZ delete If RegReadValue(hDefKey, sDelKeyName, sName, sValue, "REG_MULTI_SZ") AND NOT fRegMultiSZ Then LogOnly " - Disallowing unsafe delete of REG_MULTI_SZ: " & HiveString(hDefKey) & "\" & sDelKeyName & sName Exit Sub End If ' execute delete operation If Not fDetectOnly Then LogOnly " - Delete registry value: " & HiveString(hDefKey) & "\" & sDelKeyName & " -> " & sName iRetVal = 0 iRetVal = oReg.DeleteValue(hDefKey, sDelKeyName, sName) CheckError "RegDeleteValue" If NOT (iRetVal = 0) Then LogOnly " Delete failed. Return value: " & iRetVal SetError ERROR_STAGE2 End If Else LogOnly " - Preview mode. Disallowing delete registry value: " & HiveString(hDefKey) & "\" & sDelKeyName & " -> " & sName End If On Error Goto 0 End Sub 'RegDeleteValue '------------------------------------------------------------------------------- ' RegDeleteKey ' ' Wrappper around RegDeleteKeyEx to handle 64bit '------------------------------------------------------------------------------- Sub RegDeleteKey(hDefKey, sSubKeyName) Dim sDelKeyName Dim fKeep ' ensure trailing "\" sSubKeyName = sSubKeyName & "\" While InStr(sSubKeyName, "\\") > 0 sSubKeyName = Replace(sSubKeyName, "\\", "\") Wend fKeep = dicKeepReg.Exists(LCase(sSubKeyName)) If (NOT fKeep AND f64) Then fKeep = dicKeepReg.Exists(LCase(Wow64Key(hDefKey, sSubKeyName))) If fKeep Then LogOnly " - Disallowing the delete of still required keypath element: " & HiveString(hDefKey) & "\" & sSubKeyName If NOT fForce Then Exit Sub End If ' check on forced delete If fKeep Then LogOnly " - Enforced delete of still required keypath element: " & HiveString(hDefKey) & "\" & sSubKeyName LogOnly " Remaining applications will need a repair!" End If If Len(sSubKeyName) > 1 Then 'Strip of trailing "\" sSubKeyName = Left(sSubKeyName, Len(sSubKeyName) - 1) End If ' ensure key exists If RegKeyExists(hDefKey, sSubKeyName) Then sDelKeyName = sSubKeyName ElseIf f64 AND RegKeyExists(hDefKey, Wow64Key(hDefKey, sSubKeyName)) Then sDelKeyName = Wow64Key(hDefKey, sSubKeyName) Else LogOnly " - Key not found. Cannot delete key: " & HiveString(hDefKey) & "\" & sSubKeyName Exit Sub End If ' execute delete If Not fDetectOnly Then LogOnly " - Delete registry key: " & HiveString(hDefKey) & "\" & sDelKeyName On Error Resume Next RegDeleteKeyEx hDefKey, sDelKeyName On Error Goto 0 Else LogOnly " - Preview mode. Disallowing delete of registry key: " & HiveString(hDefKey) & "\" & sSubKeyName End If End Sub 'RegDeleteKey '------------------------------------------------------------------------------- ' RegDeleteKeyEx ' ' Recursively delete a registry structure '------------------------------------------------------------------------------- Sub RegDeleteKeyEx(hDefKey, sSubKeyName) Dim arrSubkeys Dim sSubkey Dim iRetVal 'Strip of trailing "\" If Len(sSubKeyName) > 1 Then If Right(sSubKeyName, 1) = "\" Then sSubKeyName = Left(sSubKeyName, Len(sSubKeyName) - 1) End If On Error Resume Next ' exception handler If (hDefKey = HKLM) AND (sSubKeyName = "SOFTWARE\Microsoft\Office\15.0\ClickToRun") Then iRetVal = oWShell.Run("reg delete HKLM\SOFTWARE\Microsoft\Office\15.0\ClickToRun /f", 0, True) Exit Sub End If ' regular recursion oReg.EnumKey hDefKey, sSubKeyName, arrSubkeys If IsArray(arrSubkeys) Then For Each sSubkey In arrSubkeys RegDeleteKeyEx hDefKey, sSubKeyName & "\" & sSubkey Next End If If Not fDetectOnly Then iRetVal = 0 iRetVal = oReg.DeleteKey(hDefKey, sSubKeyName) If NOT (iRetVal = 0) Then LogOnly " Delete failed. Return value: "&iRetVal End If On Error Goto 0 End Sub 'RegDeleteKeyEx '------------------------------------------------------------------------------- ' Wow64Key ' ' Return the 32bit regkey location on a 64bit environment '------------------------------------------------------------------------------- Function Wow64Key(hDefKey, sSubKeyName) Dim iPos Select Case hDefKey Case HKCU If Left(sSubKeyName, 17) = "Software\Classes\" Then Wow64Key = Left(sSubKeyName, 17) & "Wow6432Node\" & Right(sSubKeyName, Len(sSubKeyName) - 17) Else iPos = InStr(sSubKeyName, "\") Wow64Key = Left(sSubKeyName, iPos) & "Wow6432Node\" & Right(sSubKeyName, Len(sSubKeyName) - iPos) End If Case HKLM If Left(sSubKeyName, 17) = "Software\Classes\" Then Wow64Key = Left(sSubKeyName, 17) & "Wow6432Node\" & Right(sSubKeyName, Len(sSubKeyName) - 17) Else iPos = InStr(sSubKeyName, "\") Wow64Key = Left(sSubKeyName, iPos) & "Wow6432Node\" & Right(sSubKeyName, Len(sSubKeyName) - iPos) End If Case Else Wow64Key = "Wow6432Node\" & sSubKeyName End Select 'hDefKey End Function 'Wow64Key '------------------------------------------------------------------------------- ' RemoveDuplicates ' ' Remove duplicate entries from a one dimensional array '------------------------------------------------------------------------------- Function RemoveDuplicates(Array) Dim Item Dim dicNoDupes Set dicNoDupes = CreateObject("Scripting.Dictionary") For Each Item in Array If Not dicNoDupes.Exists(Item) Then dicNoDupes.Add Item,Item Next 'Item RemoveDuplicates = dicNoDupes.Keys End Function 'RemoveDuplicates '------------------------------------------------------------------------------- ' CheckError ' ' Checks the status of 'Err' and logs the error details if <> 0 '------------------------------------------------------------------------------- Sub CheckError(sModule) If Err <> 0 Then LogOnly " " & Now & " - " & sModule & " - Source: " & Err.Source & "; Err# (Hex): " & Hex( Err ) & _ "; Err# (Dec): " & Err & "; Description : " & Err.Description End If 'Err = 0 Err.Clear End Sub '------------------------------------------------------------------------------- ' Log ' ' Echos the log string to the Cmd window and the log file '------------------------------------------------------------------------------- Sub Log (sLog) wscript.echo sLog LogStream.WriteLine sLog End Sub 'Log '------------------------------------------------------------------------------- ' LogOnly ' ' Commits the log string to the log file '------------------------------------------------------------------------------- Sub LogOnly (sLog) LogStream.WriteLine sLog End Sub 'Log '------------------------------------------------------------------------------- ' InScope ' ' Check if ProductCode is in scope for removal '------------------------------------------------------------------------------- 'Check if ProductCode is in scope Function InScope(sProductCode) Dim fInScope Dim sProd fInScope = False If Len(sProductCode) = 38 Then sProd = UCase(sProductCode) Select Case OVERSIONMAJOR Case "11" If Right(sProd,PRODLEN)=OFFICEID Then InScope = True Case "12", "14" If Right(sProd,PRODLEN)=OFFICEID AND Mid(sProd,4,2) = OVERSIONMAJOR Then fInScope = True Case "15" If Right(sProd,PRODLEN)=OFFICEID AND Mid(sProd,4,2) = OVERSIONMAJOR Then Select Case Mid(sProd,11,4) Case "007E", "008F", "008C", "24E1", "237A" fInScope = True Case Else End Select End If ' Microsoft Online Services Sign-in Assistant (x64 ship and x86 ship) If sProd = "{6C1ADE97-24E1-4AE4-AEDD-86D3A209CE60}" Then fInScope = True If sProd = "{9520DDEB-237A-41DB-AA20-F2EF2360DCEB}" Then fInScope = True Case Else End Select End If '38 InScope = fInScope End Function 'InScope '------------------------------------------------------------------------------- ' CheckDelete ' ' Check a ProductCode is known to stay installed '------------------------------------------------------------------------------- Function CheckDelete(sProductCode) CheckDelete = False ' ensure valid GUID length If NOT Len(sProductCode) = 38 Then Exit Function ' only care if it's in the expected ProductCode pattern If NOT InScope(sProductCode) Then Exit Function ' check if it's a known product that should be kept If dicKeepProd.Exists(UCase(sProductCode)) OR dicKeepSku.Exists(UCase(sProductCode)) Then Exit Function CheckDelete = True End Function 'CheckDelete '------------------------------------------------------------------------------- ' DeleteService ' ' Delete a service '------------------------------------------------------------------------------- 'Delete a service Sub DeleteService(sName) Dim Services, srvc, Processes, process Dim sQuery, sStates, sProcessName, sCmd Dim iRet On Error Resume Next sStates = "STARTED;RUNNING" sQuery = "Select * From Win32_Service Where Name='" & sName & "'" Set Services = oWmiLocal.Execquery(sQuery) ' stop and delete the service For Each srvc in Services Log " Found service " & sName & " (" & srvc.DisplayName & ") in state " & srvc.State ' get the process name sProcessName = Trim(Replace(Mid(srvc.PathName, InStrRev(srvc.PathName,"\") + 1), chr(34), "")) ' stop the service If InStr(sStates, UCase(srvc.State)) > 0 Then iRet = srvc.StopService() LogOnly " attempt to stop service " & sName & " returned: " & iRet End If ' ensure no more instances of the service are running Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process Where Name='" & sProcessName & "'") For Each process in Processes iRet = process.Terminate() Next 'Process If fDetectOnly Then Log " Not deleting service " & sName & " in preview mode" Exit Sub End If iRet = srvc.Delete() Log " Delete service " & sName & " returned: " & iRet Next 'srvc ' check if service got deleted Set Services = oWmiLocal.Execquery(sQuery) For Each srvc in Services ' failed to delete service. retry with 'sc' command sLog " Deleting service " & sName & " failed. Retry delete using 'SC' command" sCmd = "sc delete " & sName iRet = oWShell.Run(sCmd, 0, True) Next 'srvc Set Services = Nothing Err.Clear On Error Goto 0 End Sub 'DeleteService '------------------------------------------------------------------------------- ' SetupRetVal ' ' Translation for known uninstall return values '------------------------------------------------------------------------------- Function SetupRetVal(RetVal) Select Case RetVal Case 0 : SetupRetVal = "Success" 'msiexec return values Case 1259 : SetupRetVal = "APPHELP_BLOCK" Case 1601 : SetupRetVal = "INSTALL_SERVICE_FAILURE" Case 1602 : SetupRetVal = "INSTALL_USEREXIT" Case 1603 : SetupRetVal = "INSTALL_FAILURE" Case 1604 : SetupRetVal = "INSTALL_SUSPEND" Case 1605 : SetupRetVal = "UNKNOWN_PRODUCT" Case 1606 : SetupRetVal = "UNKNOWN_FEATURE" Case 1607 : SetupRetVal = "UNKNOWN_COMPONENT" Case 1608 : SetupRetVal = "UNKNOWN_PROPERTY" Case 1609 : SetupRetVal = "INVALID_HANDLE_STATE" Case 1610 : SetupRetVal = "BAD_CONFIGURATION" Case 1611 : SetupRetVal = "INDEX_ABSENT" Case 1612 : SetupRetVal = "INSTALL_SOURCE_ABSENT" Case 1613 : SetupRetVal = "INSTALL_PACKAGE_VERSION" Case 1614 : SetupRetVal = "PRODUCT_UNINSTALLED" Case 1615 : SetupRetVal = "BAD_QUERY_SYNTAX" Case 1616 : SetupRetVal = "INVALID_FIELD" Case 1618 : SetupRetVal = "INSTALL_ALREADY_RUNNING" Case 1619 : SetupRetVal = "INSTALL_PACKAGE_OPEN_FAILED" Case 1620 : SetupRetVal = "INSTALL_PACKAGE_INVALID" Case 1621 : SetupRetVal = "INSTALL_UI_FAILURE" Case 1622 : SetupRetVal = "INSTALL_LOG_FAILURE" Case 1623 : SetupRetVal = "INSTALL_LANGUAGE_UNSUPPORTED" Case 1624 : SetupRetVal = "INSTALL_TRANSFORM_FAILURE" Case 1625 : SetupRetVal = "INSTALL_PACKAGE_REJECTED" Case 1626 : SetupRetVal = "FUNCTION_NOT_CALLED" Case 1627 : SetupRetVal = "FUNCTION_FAILED" Case 1628 : SetupRetVal = "INVALID_TABLE" Case 1629 : SetupRetVal = "DATATYPE_MISMATCH" Case 1630 : SetupRetVal = "UNSUPPORTED_TYPE" Case 1631 : SetupRetVal = "CREATE_FAILED" Case 1632 : SetupRetVal = "INSTALL_TEMP_UNWRITABLE" Case 1633 : SetupRetVal = "INSTALL_PLATFORM_UNSUPPORTED" Case 1634 : SetupRetVal = "INSTALL_NOTUSED" Case 1635 : SetupRetVal = "PATCH_PACKAGE_OPEN_FAILED" Case 1636 : SetupRetVal = "PATCH_PACKAGE_INVALID" Case 1637 : SetupRetVal = "PATCH_PACKAGE_UNSUPPORTED" Case 1638 : SetupRetVal = "PRODUCT_VERSION" Case 1639 : SetupRetVal = "INVALID_COMMAND_LINE" Case 1640 : SetupRetVal = "INSTALL_REMOTE_DISALLOWED" Case 1641 : SetupRetVal = "SUCCESS_REBOOT_INITIATED" Case 1642 : SetupRetVal = "PATCH_TARGET_NOT_FOUND" Case 1643 : SetupRetVal = "PATCH_PACKAGE_REJECTED" Case 1644 : SetupRetVal = "INSTALL_TRANSFORM_REJECTED" Case 1645 : SetupRetVal = "INSTALL_REMOTE_PROHIBITED" Case 1646 : SetupRetVal = "PATCH_REMOVAL_UNSUPPORTED" Case 1647 : SetupRetVal = "UNKNOWN_PATCH" Case 1648 : SetupRetVal = "PATCH_NO_SEQUENCE" Case 1649 : SetupRetVal = "PATCH_REMOVAL_DISALLOWED" Case 1650 : SetupRetVal = "INVALID_PATCH_XML" Case 3010 : SetupRetVal = "SUCCESS_REBOOT_REQUIRED" Case Else : SetupRetVal = "Unknown Return Value" End Select End Function 'SetupRetVal '------------------------------------------------------------------------------- ' DeleteFile ' ' Wrapper to delete a file '------------------------------------------------------------------------------- Sub DeleteFile(sFile) Dim File, attr Dim sDelFile, sFileName, sNewPath Dim fKeep On Error Resume Next fKeep = dicKeepFolder.Exists(LCase(sFile)) If (NOT fKeep AND f64) Then fKeep = dicKeepFolder.Exists(LCase(Wow64Folder(sFile))) If fKeep Then LogOnly " - Disallowing the delete of still required keypath element: " & sFile If NOT fForce Then Exit Sub End If ' check on forced delete If fKeep Then LogOnly " - Enforced delete of still required keypath element: " & sFile LogOnly " Remaining applications will need a repair!" End If If oFso.FileExists(sFile) Then sDelFile = sFile ElseIf f64 AND oFso.FileExists(Wow64Folder(sFile)) Then sDelFile = Wow64Folder(sFile) Else LogOnly " - Path not found. Cannot not delete folder: " & sFile Exit Sub End If If Not fDetectOnly Then LogOnly " - Delete file: " & sDelFile Set File = oFso.GetFile(sDelFile) ' ensure read-only flag is not set attr = File.Attributes If CBool(attr AND 1) Then File.Attributes = attr AND (attr - 1) ' add folder to empty folder cleanup list If NOT dicDelFolder.Exists(File.ParentFolder.Path) Then dicDelFolder.Add File.ParentFolder.Path, File.ParentFolder.Path ' delete the file sFile = File.Path File.Delete True Set File = Nothing If Err <> 0 Then CheckError "DeleteFile" ' schedule file for delete on next reboot ScheduleDeleteFile sFile End If 'Err <> 0 Else LogOnly " - Preview mode. Disallowing delete for folder: " & sDelFile End If On Error Goto 0 End Sub 'DeleteFile '------------------------------------------------------------------------------- ' DeleteFolder ' ' Wrapper to delete a folder '------------------------------------------------------------------------------- Sub DeleteFolder(sFolder) Dim Folder, fld, attr Dim sDelFolder, sFolderName, sNewPath, sCmd Dim fKeep ' ensure trailing "\" ' trailing \ is required for dicKeepFolder comparisons sFolder = sFolder & "\" While InStr(sFolder,"\\")>0 sFolder = Replace(sFolder,"\\","\") Wend ' prevent delete of folders that are known to be still required fKeep = dicKeepFolder.Exists(LCase(sFolder)) If (NOT fKeep AND f64) Then fKeep = dicKeepFolder.Exists(LCase(Wow64Folder(sFolder))) If fKeep Then LogOnly " - Disallowing the delete of still required keypath element: " & sFolder If NOT fForce Then Exit Sub End If ' check on forced delete If fKeep Then LogOnly " - Enforced delete of still required keypath element: " & sFolder LogOnly " Remaining applications will need a repair!" End If ' strip trailing "\" If Len(sFolder) > 1 Then sFolder = Left(sFolder, Len(sFolder) - 1) End If On Error Resume Next If oFso.FolderExists(sFolder) Then sDelFolder = sFolder ElseIf f64 AND oFso.FolderExists(Wow64Folder(sFolder)) Then sDelFolder = Wow64Folder(sFolder) Else LogOnly " - Path not found. Cannot not delete folder: " & sFolder Exit Sub End If If Not fDetectOnly Then LogOnly " - Delete folder: " & sDelFolder Set Folder = oFso.GetFolder(sDelFolder) ' ensure to remove read only flag attr = Folder.Attributes If CBool(attr AND 1) Then Folder.Attributes = attr AND (attr - 1) ' add to empty folder cleanup list If NOT dicDelFolder.Exists(Folder.Path) Then dicDelFolder.Add Folder.Path, Folder.Path ' delete the folder ' for performance reasons try 'rd' first Set Folder = Nothing sCmd = "cmd.exe /c rd /s " & chr(34) & sDelFolder & chr(34) & " /q" oWShell.Run sCmd, 0, True If NOT oFso.FolderExists(sDelFolder) Then Exit Sub ' rd didn't work check with FileSystemObject Set Folder = oFso.GetFolder(sDelFolder) Folder.Delete True Set Folder = Nothing ' error handling If Err <> 0 Then Select Case Err Case 70 ' Access Denied ' Retry after closing running processes CheckError "DeleteFolder" If NOT fRerun Then CloseOfficeApps ' attempt 'rd' command LogOnly " Attempt to remove with 'rd' command" sCmd = "cmd.exe /c rd /s " & chr(34) & sDelFolder & chr(34) & " /q" oWShell.Run sCmd, 0, True If NOT oFso.FolderExists(sDelFolder) Then Exit Sub End If Case 76 ' check on invalid path lengt issues Err 76 (0x4C) "Path not found" ' attempt 'rd' command CheckError "DeleteFolder" LogOnly " Attempt to remove with 'rd' command" sCmd = "cmd.exe /c rd /s " & chr(34) & sDelFolder & chr(34) & " /q" oWShell.Run sCmd, 0, True If NOT oFso.FolderExists(sDelFolder) Then Exit Sub End Select ' stil failed! Log " Failed to delete folder: " & sDelFolder CheckError "DeleteFolder" ' try to delete as many folder contents as possible ' before the recursive error handling is called Set Folder = oFso.GetFolder(sDelFolder) For Each fld in Folder.Subfolders sCmd = "cmd.exe /c rd /s " & chr(34) & fld.Path & chr(34) & " /q" oWShell.Run sCmd, 0, True Next 'fld sCmd = "cmd.exe /c del " & chr(34) & fld.Path & "\*.*" & chr(34) oWShell.Run sCmd, 0, True Set Folder = Nothing ' schedule an additional run of the tool after reboot If NOT fRerun Then Rerun ' schedule folder for delete on next reboot ScheduleDeleteFolder sDelFolder End If 'Err <> 0 Else LogOnly " - Preview mode. Disallowing delete of folder: " & sDelFolder End If On Error Goto 0 End Sub 'DeleteFolder Sub DeleteFolder_WMI (sFolder) Dim Folder, Folders Dim sWqlFolder Dim iRet sWqlFolder = Replace(sFolder, "\", "\\") Set Folders = oWmiLocal.ExecQuery ("Select * from Win32_Directory where name = '" & sWqlFolder & "'") For Each Folder in Folders iRet = Folder.Delete Next 'Folder LogOnly " Delete (wmi) for folder " & sFolder & " returned: " & iRet End Sub '------------------------------------------------------------------------------- ' Wow64Folder ' ' Returns the WOW folder structure to handle folder-path operations on ' 64 bit environments '------------------------------------------------------------------------------- Function Wow64Folder(sFolder) If LCase(Left(sFolder, Len(sWinDir & "\System32"))) = LCase(sWinDir & "\System32") Then Wow64Folder = sWinDir & "\syswow64" & Right(sFolder, Len(sFolder) - Len(sWinDir & "\System32")) ElseIf LCase(Left(sFolder, Len(sProgramFiles))) = LCase(sProgramFiles) Then Wow64Folder = sProgramFilesX86 & Right(sFolder, Len(sFolder) - Len(sProgramFiles)) Else Wow64Folder = "?" 'Return invalid string to ensure the folder cannot exist End If End Function 'Wow64Folder '------------------------------------------------------------------------------- ' ScheduleDeleteFile ' ' Adds a file to the list of items to delete on reboot '------------------------------------------------------------------------------- Sub ScheduleDeleteFile (sFile) If NOT dicDelInUse.Exists(sFile) Then dicDelInUse.Add sFile, sFile Else Exit Sub LogOnly " - Adding file in use for delete on reboot: " & sFile fRebootRequired = True SetError ERROR_REBOOT_REQUIRED End Sub 'ScheduleDeleteFile '------------------------------------------------------------------------------- ' ScheduleDeleteFolder ' ' Recursively adds a folder and its contents to the list of ' items to delete on reboot '------------------------------------------------------------------------------- Sub ScheduleDeleteFolder (sFolder) Dim oFolder, fld, file, attr Set oFolder = oFso.GetFolder(sFolder) ' exclude hidden system folders attr = oFolder.Attributes If CBool(attr AND 6) Then Exit Sub For Each fld In oFolder.SubFolders DeleteFolder fld.Path Next For Each file In oFolder.Files DeleteFile file.Path Next If NOT dicDelInUse.Exists(oFolder.Path) Then dicDelInUse.Add oFolder.Path, "" Else Exit Sub LogOnly " - Adding folder for delete on reboot: " & oFolder.Path fRebootRequired = True SetError ERROR_REBOOT_REQUIRED End Sub 'ScheduleDeleteFile '------------------------------------------------------------------------------- ' ScheduleDeleteEx ' ' Schedules the delete of files/folders in use on next reboot by adding ' affected files/folders to the PendingFileRenameOperations registry entry '------------------------------------------------------------------------------- Sub ScheduleDeleteEx () Dim key, hDefKey, sKeyName, sValueName Dim i Dim arrData hDefKey = HKLM sKeyName = "SYSTEM\CurrentControlSet\Control\Session Manager" sValueName = "PendingFileRenameOperations" Log " - Adding " & dicDelInUse.Count & " PendingFileRenameOperations" & " (" & Time & ")" If NOT RegValExists(hDefKey, sKeyName, sValueName) Then ReDim arrData(-1) Else oReg.GetMultiStringValue hDefKey, sKeyName, sValueName, arrData End If i = UBound(arrData) + 1 ReDim Preserve arrData(UBound(arrData) + (dicDelInUse.Count * 2)) For Each key in dicDelInUse.Keys LogOnly " " & key arrData(i) = "\??\" & key arrData(i + 1) = "" i = i + 2 Next 'key oReg.SetMultiStringValue hDefKey, sKeyName, sValueName, arrData End Sub 'ScheduleDeleteEx '------------------------------------------------------------------------------- ' DeleteEmptyFolders ' ' Delete an empty folder structure '------------------------------------------------------------------------------- Sub DeleteEmptyFolders Dim Folder Dim sFolder ' cosmetic' task don't fail on error On Error Resume Next For Each sFolder in dicDelFolder.Keys If oFso.FolderExists(sFolder) Then Set Folder = oFso.GetFolder(sFolder) If (Folder.Subfolders.Count = 0) AND (Folder.Files.Count = 0) Then Set Folder = Nothing SmartDeleteFolder sFolder End If End If Next 'sFolder CheckError "DeleteEmptyFolders" On Error Goto 0 End Sub 'DeleteEmptyFolders '------------------------------------------------------------------------------- ' SmartDeleteFolder ' ' Wrapper to delete a folder and the empty parent folder structure '------------------------------------------------------------------------------- Sub SmartDeleteFolder(sFolder) Dim sDelFolder If oFso.FolderExists(sFolder) Then sDelFolder = sFolder ElseIf f64 AND oFso.FolderExists(Wow64Folder(sFolder)) Then sDelFolder = Wow64Folder(sFolder) Else Exit Sub End If If Not fDetectOnly Then LogOnly " - Request SmartDelete for folder: " & sDelFolder SmartDeleteFolderEx sDelFolder Else LogOnly " - Preview mode. Disallowing SmartDelete request for folder: " & sDelFolder End If End Sub 'SmartDeleteFolder '------------------------------------------------------------------------------- ' SmartDeleteFolderEx ' ' Executes the folder delete operation(s) '------------------------------------------------------------------------------- Sub SmartDeleteFolderEx(sFolder) Dim Folder On Error Resume Next DeleteFolder sFolder : CheckError "SmartDeleteFolderEx" On Error Goto 0 Set Folder = oFso.GetFolder(oFso.GetParentFolderName(sFolder)) If (Folder.Subfolders.Count = 0) AND (Folder.Files.Count = 0) Then SmartDeleteFolderEx(Folder.Path) End Sub 'SmartDeleteFolderEx '------------------------------------------------------------------------------- ' RestoreExplorer ' ' Ensure Windows Explorer is restarted if needed '------------------------------------------------------------------------------- Sub RestoreExplorer Dim Processes, Result, oAT, DateTime, JobID Dim sCmd 'Non critical routine. Don't fail on error On Error Resume Next wscript.sleep 1000 Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process Where Name='explorer.exe'") If Processes.Count < 1 Then oWShell.Run "explorer.exe" 'To handle this in case of System context, schedule and run as interactive task oWShell.Run "SCHTASKS /Create /TN OffScrEx /TR explorer /SC ONCE /ST 12:00 /IT", 0, True oWShell.Run "SCHTASKS /Run /TN OffScrEx", 0, True oWShell.Run "SCHTASKS /Delete /TN OffScrEx /F", 0, False End If On Error Goto 0 End Sub 'RestoreExploer '------------------------------------------------------------------------------- ' MyJoin ' ' Replacement function to the internal Join function to prevent failures ' that were seen in some instances '------------------------------------------------------------------------------- Function MyJoin(arrToJoin, sSeparator) Dim sJoined Dim i sJoined = "" If IsArray(arrToJoin) Then For i = 0 To UBound(arrToJoin) sJoined = sJoined & arrToJoin(i) & sSeparator Next 'i End If If Len(sJoined) > 1 Then sJoined = Left(sJoined, Len(sJoined) - 1) MyJoin = sJoined End Function '------------------------------------------------------------------------------- ' Rerun ' ' Flag need for reboot and schedule autorun to run the tool again on reboot. '------------------------------------------------------------------------------- Sub Rerun () Dim sValue ' check if Rerun has already been called If fRerun Then Exit Sub ' set Rerun flag fRerun = True ' check if the previous run already initiated the Rerun If RegReadValue(HKCU, "SOFTWARE\Microsoft\Office\15.0\CleanC2R", "Rerun", sValue, "REG_DWORD") Then ' Rerun has already been tried Log vbCrLf & "Error: Removal failed" SetError ERROR_DCAF_FAILURE Exit Sub End If fRebootRequired = True SetError ERROR_REBOOT_REQUIRED SetError ERROR_INCOMPLETE ' cache the script to the local scrub folder oFso.CopyFile WScript.scriptFullName, sScrubDir & "\" & SCRIPTFILE oReg.CreateKey HKCU, "SOFTWARE" oReg.CreateKey HKCU, "SOFTWARE\Microsoft" oReg.CreateKey HKCU, "SOFTWARE\Microsoft\Office" oReg.CreateKey HKCU, "SOFTWARE\Microsoft\Office\15.0" oReg.CreateKey HKCU, "SOFTWARE\Microsoft\Office\15.0\CleanC2R" oReg.SetDWordValue HKCU, "SOFTWARE\Microsoft\Office\15.0\CleanC2R", "Rerun", 1 fSetRunOnce = True ' oReg.CreateKey HKCU, "SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" ' oReg.SetStringValue HKCU, "SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce", "CleanC2R", "cscript.exe " & chr(34) & sScrubDir & "\" & SCRIPTFILE & chr(34) End Sub '------------------------------------------------------------------------------- ' SetRunOnce ' ' Create a RunOnce entry to resume setup after a reboot '------------------------------------------------------------------------------- Sub SetRunOnce Dim sValue oReg.CreateKey HKCU, "SOFTWARE\Microsoft\Windows\CurrentVersion" oReg.CreateKey HKCU, "SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" sValue = "cscript.exe " & chr(34) & sScrubDir & "\" & SCRIPTFILE & chr(34) & " /NoElevate /Relaunched" oReg.SetStringValue HKCU, "SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce", "O15CleanUp", sValue End Sub 'SetRunOnce '------------------------------------------------------------------------------- ' CsvWrite ' ' The csv log will always be a single line. ' Overwrite the file each time '------------------------------------------------------------------------------- Sub CsvWrite Dim CsvLog, sCsvLog 'On Error Resume Next sCsvLog = CSVLOGFOLDER & arrResult(COL_COMPUTERNAME) & ".csv" Set CsvLog = oFso.CreateTextFile(sCsvLog, True, False) If Err <> 0 Then Err.Clear sCsvLog = sLogDir & "\" & arrResult(COL_COMPUTERNAME) & ".csv" Set CsvLog = oFso.CreateTextFile(sCsvLog, True, False) End If CsvLog.WriteLine MyJoin(arrResult,";") CsvLog.Close On Error Goto 0 End Sub 'CsvWrite '' SIG '' Begin signature block '' SIG '' MIIa3QYJKoZIhvcNAQcCoIIazjCCGsoCAQExCzAJBgUr '' SIG '' DgMCGgUAMGcGCisGAQQBgjcCAQSgWTBXMDIGCisGAQQB '' SIG '' gjcCAR4wJAIBAQQQTvApFpkntU2P5azhDxfrqwIBAAIB '' SIG '' AAIBAAIBAAIBADAhMAkGBSsOAwIaBQAEFEgniqMP3Mbc '' SIG '' CsVNNLJputNH7e01oIIWEzCCBLowggOioAMCAQICCmEC '' SIG '' kkoAAAAAACAwDQYJKoZIhvcNAQEFBQAwdzELMAkGA1UE '' SIG '' BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV '' SIG '' BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD '' SIG '' b3Jwb3JhdGlvbjEhMB8GA1UEAxMYTWljcm9zb2Z0IFRp '' SIG '' bWUtU3RhbXAgUENBMB4XDTEyMDEwOTIyMjU1OVoXDTEz '' SIG '' MDQwOTIyMjU1OVowgbMxCzAJBgNVBAYTAlVTMRMwEQYD '' SIG '' VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k '' SIG '' MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x '' SIG '' DTALBgNVBAsTBE1PUFIxJzAlBgNVBAsTHm5DaXBoZXIg '' SIG '' RFNFIEVTTjpCOEVDLTMwQTQtNzE0NDElMCMGA1UEAxMc '' SIG '' TWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCCASIw '' SIG '' DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM1jw/ei '' SIG '' tUfZ+TmUU6xrj6Z5OCH00W49FTgWwXMsmY/74Dxb4aJM '' SIG '' i7Kri7TySse5k1DRJvWHU7B6dfNHDxcrZyxk62DnSozg '' SIG '' i17EVmk3OioEXRcByL+pt9PJq6ORqIHjPy232OTEeAB5 '' SIG '' Oc/9x2TiIxJ4ngx2J0mPmqwOdOMGVVVJyO2hfHBFYX6y '' SIG '' cRYe4cFBudLSMulSJPM2UATX3W88SdUL1HZA/GVlE36V '' SIG '' UTrV/7iap1drSxXlN1gf3AANxa7q34FH+fBSrubPWqzg '' SIG '' FEqmcZSA+v2wIzBg6YNgrA4kHv8R8uelVWKV7p9/ninW '' SIG '' zUsKdoPwQwTfBkkg8lNaRLBRejkCAwEAAaOCAQkwggEF '' SIG '' MB0GA1UdDgQWBBTNGaxhTZRnK/avlHVZ2/BYAIOhOjAf '' SIG '' BgNVHSMEGDAWgBQjNPjZUkZwCu1A+3b7syuwwzWzDzBU '' SIG '' BgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vY3JsLm1pY3Jv '' SIG '' c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNyb3Nv '' SIG '' ZnRUaW1lU3RhbXBQQ0EuY3JsMFgGCCsGAQUFBwEBBEww '' SIG '' SjBIBggrBgEFBQcwAoY8aHR0cDovL3d3dy5taWNyb3Nv '' SIG '' ZnQuY29tL3BraS9jZXJ0cy9NaWNyb3NvZnRUaW1lU3Rh '' SIG '' bXBQQ0EuY3J0MBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0G '' SIG '' CSqGSIb3DQEBBQUAA4IBAQBRHNbfNh3cgLwCp8aZ3xbI '' SIG '' kAZpFZoyufNkENKK82IpG3mPymCps13E5BYtNYxEm/H0 '' SIG '' XGGkQa6ai7pQ0Wp5arNijJ1NUVALqY7Uv6IQwEfVTnVS '' SIG '' iR4/lmqPLkAUBnLuP3BZkl2F7YOZ+oKEnuQDASETqyfW '' SIG '' zHFJ5dod/288CU7VjWboDMl/7jEUAjdfe2nsiT5FfyVE '' SIG '' 5x8a1sUaw0rk4fGEmOdP+amYpxhG7IRs7KkDCv18elId '' SIG '' nGukqA+YkqSSeFwreON9ssfZtnB931tzU7+q1GZQS/DJ '' SIG '' O5WF5cFKZZ0lWFC7IFSReTobB1xqVyivMcef58Md7kf9 '' SIG '' J9d/z3TcZcU/MIIFijCCBHKgAwIBAgIKaoENdwACAPSq '' SIG '' 3zANBgkqhkiG9w0BAQUFADAfMR0wGwYDVQQDExRNU0lU '' SIG '' IEVudGVycHJpc2UgQ0EgMTAeFw0xMjAzMjkxNzA4MjJa '' SIG '' Fw0xMzAzMjkxNzA4MjJaMIGXMQswCQYDVQQGEwJVUzET '' SIG '' MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk '' SIG '' bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 '' SIG '' aW9uMQ0wCwYDVQQLEwRNT1BSMTIwMAYDVQQDEylNaWNy '' SIG '' b3NvZnQgQ29ycG9yYXRpb24gKEludGVybmFsIFVzZSBP '' SIG '' bmx5KTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC '' SIG '' ggEBAPkvnXxc1N/fx9GPkWtq4ognoSiQgNx4o+HmF37p '' SIG '' xHwls/sLcOTI6OyXjloXf3Y+IjuE/kqHZLQD5mHGjPRM '' SIG '' 7EBortDOyRSsuaYxub8DXqe70Hu4nSWeiJqBrmLKBxw3 '' SIG '' UL1Xh9tR/EXcVYXI5TJGFINktettFQrYuPL/AXoYhVqT '' SIG '' zqjZcAV4pg9dEeajxy1hyjFETrdZpY3TqIdg6vHqnFRN '' SIG '' KCombT5bz5/877KdGhJ4TO9GDpdPcyK8lk/tJrIKbMwo '' SIG '' 8WNq5JADZYHddOWX+eDLZPCePnljTumjoHgcRUkM9/UW '' SIG '' lli/+D28eUrC5ogXhgIo7wWOhUIsm9iijJ7bcEkCAwEA '' SIG '' AaOCAk0wggJJMBsGCSsGAQQBgjcVCgQOMAwwCgYIKwYB '' SIG '' BQUHAwMwOwYJKwYBBAGCNxUHBC4wLAYkKwYBBAGCNxUI '' SIG '' g8+JTa3yAoWhnwyC+sp9geH7dIFP0cFzy4JTAgFkAgEB '' SIG '' MIGlBggrBgEFBQcBAQSBmDCBlTBABggrBgEFBQcwAoY0 '' SIG '' aHR0cDovL2NvcnBwa2kvYWlhL01TSVQlMjBFbnRlcnBy '' SIG '' aXNlJTIwQ0ElMjAxKDIpLmNydDBRBggrBgEFBQcwAoZF '' SIG '' aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9tc2Nv '' SIG '' cnAvTVNJVCUyMEVudGVycHJpc2UlMjBDQSUyMDEoMiku '' SIG '' Y3J0MB0GA1UdDgQWBBSGtr5TDHXciX7VG+efeqwmM8hV '' SIG '' lDALBgNVHQ8EBAMCB4AwgeIGA1UdHwSB2jCB1zCB1KCB '' SIG '' 0aCBzoY0aHR0cDovL2NvcnBwa2kvY3JsL01TSVQlMjBF '' SIG '' bnRlcnByaXNlJTIwQ0ElMjAxKDIpLmNybIZLaHR0cDov '' SIG '' L21zY3JsLm1pY3Jvc29mdC5jb20vcGtpL21zY29ycC9j '' SIG '' cmwvTVNJVCUyMEVudGVycHJpc2UlMjBDQSUyMDEoMiku '' SIG '' Y3JshklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtp '' SIG '' L21zY29ycC9jcmwvTVNJVCUyMEVudGVycHJpc2UlMjBD '' SIG '' QSUyMDEoMikuY3JsMB8GA1UdIwQYMBaAFPT6p0kChvQv '' SIG '' PTsxuNiVeq81KeLbMBMGA1UdJQQMMAoGCCsGAQUFBwMD '' SIG '' MA0GCSqGSIb3DQEBBQUAA4IBAQAMvmHLITIz6rYvkM11 '' SIG '' yQCxNBZBo020tX91QkrR76ltnNr+Wk3kX/XDoHtfN4b9 '' SIG '' zmLMfk1LdYHM9a5hd/bzstL5uTsctIneUXX6Pr3+gSiv '' SIG '' PqgnSwBTFedL3kiqdG99RusAFj+jiSoS2MYdcVMQCX1m '' SIG '' iUfBUdpHzMOSJfPsqxx0vb1GTvJy0mvq+vXXILAfm4YW '' SIG '' sQKxKbzrNiFOfkL9YW1JK0v0L+fEWQ8SyIzS8pbUAg8h '' SIG '' I0AJsa9Q9LXpaB1Pfoqg1GSXNwPIBQZxCUEDMCQ0o4Wf '' SIG '' jOTHb5J/sJPWfV35xilvE3jseayZLKfCwcW55kG8/JLH '' SIG '' pM7t3dCqQF2AtSXzMIIFuDCCA6CgAwIBAgIKYQONfAAA '' SIG '' AAAAjzANBgkqhkiG9w0BAQUFADBGMR4wHAYDVQQKExVN '' SIG '' aWNyb3NvZnQgQ29ycG9yYXRpb24xJDAiBgNVBAMTG01p '' SIG '' Y3Jvc29mdCBDb3Jwb3JhdGUgUm9vdCBDQTAeFw0xMDEw '' SIG '' MDEyMTQ3MzdaFw0xNDEwMDEyMTU3MzdaMB8xHTAbBgNV '' SIG '' BAMTFE1TSVQgRW50ZXJwcmlzZSBDQSAxMIIBIjANBgkq '' SIG '' hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAusMEwLSo/fqH '' SIG '' Z6UpWExHnIXeiBo3oNaQvwcT0i7Ok8UhVsLT9HtsfcTf '' SIG '' EIeZH0hdw415s4dFbwJ1Pkc50bgFl4HCkehB//W20Ggi '' SIG '' dQrBw0joj3z525gkm+F8ljhkHHWI6Vp8xiXtJY63V1YD '' SIG '' RFXo1m5HyO9k1H25p+U1sOur3lCVgkywui9mckobIY6X '' SIG '' iboezwgoWpiqHkl7615YdrqK6y2oY7I9zvbb0+mMUY7L '' SIG '' SjJbA9mWUwr6DowJdkBWpYndxyiYz3C8PXrP6ihTEotD '' SIG '' MjA9fEcOEr76XgeY947a0SYRg8d2q472s76TY4Y7JIQy '' SIG '' lUJRsey7KWsfKxq2lBtumQIDAQABo4IBzTCCAckwEgYJ '' SIG '' KwYBBAGCNxUBBAUCAwIAAjAjBgkrBgEEAYI3FQIEFgQU '' SIG '' N7yet+8ZGgJa8f1R0vl7cn0QuVowHQYDVR0OBBYEFPT6 '' SIG '' p0kChvQvPTsxuNiVeq81KeLbMBkGCSsGAQQBgjcUAgQM '' SIG '' HgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMB '' SIG '' Af8EBTADAQH/MB8GA1UdIwQYMBaAFCMMmIa3u2GRUMAz '' SIG '' sQbVRGiG+Qj4MIGdBgNVHR8EgZUwgZIwgY+ggYyggYmG '' SIG '' HWh0dHA6Ly9jb3JwcGtpL2NybC9tc2NyY2EuY3JshjRo '' SIG '' dHRwOi8vbXNjcmwubWljcm9zb2Z0LmNvbS9wa2kvbXNj '' SIG '' b3JwL2NybC9tc2NyY2EuY3JshjJodHRwOi8vY3JsLm1p '' SIG '' Y3Jvc29mdC5jb20vcGtpL21zY29ycC9jcmwvbXNjcmNh '' SIG '' LmNybDB1BggrBgEFBQcBAQRpMGcwKQYIKwYBBQUHMAKG '' SIG '' HWh0dHA6Ly9jb3JwcGtpL2FpYS9tc2NyY2EuY3J0MDoG '' SIG '' CCsGAQUFBzAChi5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j '' SIG '' b20vcGtpL21zY29ycC9tc2NyY2EuY3J0MA0GCSqGSIb3 '' SIG '' DQEBBQUAA4ICAQBZonHtfjwKd/UaR2awncH1eBSjViBx '' SIG '' WBPoWYYEcMY/1MDxUUJH8oPii5BogFxyOl6nAfwVRGyU '' SIG '' oisnbJf+NB4se3FJL6fn1ljcL3kBeTQdy5orW51EFhwf '' SIG '' gYvH9xLBa/nqAFuATQU39QsMNHIYSzJOlfQd9SfgtcZb '' SIG '' Tr/7zvxPIziN/Y462Z+qefJzN4bIv1r14NiorCtSWIcs '' SIG '' PxXvxzvHkK7ELyaArvuFfx6y8DrXefuIP1kZnFMVEfxz '' SIG '' +HJTDuW6FkKD3KSdjJ9hPZCQL2CCnCVEcZTESOYFa45n '' SIG '' O3bREF5Dz/D9YIM7j4FadQpTT5JHLSiB5WErr4CvXa0f '' SIG '' bt2EtXU+dQWz8aoszEOYoxiv4xOdAkhRT7yLIRFijuB2 '' SIG '' m/6XkM+maDKA21reNGHgp8Rczgal0A0likT3h9jEkGYW '' SIG '' 1DSeHtTkM78iy7AGgirgPmakj5uPCFm+jUFnd9034lHl '' SIG '' G9DJxdkNQbUsZgHw2PMi+aNEWjnAtVtR26DXjGEIk8t6 '' SIG '' 9ao7QTuq/bKBw5f39sZkIfa++imlZrdNoWxrV2ZHGiip '' SIG '' dXmCML/qDq59jp0e8Y/JQgbFhyTrDzJTwAQTd7z/KMsH '' SIG '' 94T/eZmykwtdvIeyHKchT2nY0rBnBKT2JXIvDLi8QkQp '' SIG '' yRDgJfCTwxyUVe3xgoY+RPLDrfhdNApI2XfKcjCCBgcw '' SIG '' ggPvoAMCAQICCmEWaDQAAAAAABwwDQYJKoZIhvcNAQEF '' SIG '' BQAwXzETMBEGCgmSJomT8ixkARkWA2NvbTEZMBcGCgmS '' SIG '' JomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UEAxMkTWlj '' SIG '' cm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 '' SIG '' MB4XDTA3MDQwMzEyNTMwOVoXDTIxMDQwMzEzMDMwOVow '' SIG '' dzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0 '' SIG '' b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p '' SIG '' Y3Jvc29mdCBDb3Jwb3JhdGlvbjEhMB8GA1UEAxMYTWlj '' SIG '' cm9zb2Z0IFRpbWUtU3RhbXAgUENBMIIBIjANBgkqhkiG '' SIG '' 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn6Fssd/bSJIqfGsu '' SIG '' GeG94uPFmVEjUK3O3RhOJA/u0afRTK10MCAR6wfVVJUV '' SIG '' SZQbQpKumFwwJtoAa+h7veyJBw/3DgSY8InMH8szJIed '' SIG '' 8vRnHCz8e+eIHernTqOhwSNTyo36Rc8J0F6v0LBCBKL5 '' SIG '' pmyTZ9co3EZTsIbQ5ShGLieshk9VUgzkAyz7apCQMG6H '' SIG '' 81kwnfp+1pez6CGXfvjSE/MIt1NtUrRFkJ9IAEpHZhEn '' SIG '' KWaol+TTBoFKovmEpxFHFAmCn4TtVXj+AZodUAiFABAw '' SIG '' Ru233iNGu8QtVJ+vHnhBMXfMm987g5OhYQK1HQ2x/Peb '' SIG '' sgHOIktU//kFw8IgCwIDAQABo4IBqzCCAacwDwYDVR0T '' SIG '' AQH/BAUwAwEB/zAdBgNVHQ4EFgQUIzT42VJGcArtQPt2 '' SIG '' +7MrsMM1sw8wCwYDVR0PBAQDAgGGMBAGCSsGAQQBgjcV '' SIG '' AQQDAgEAMIGYBgNVHSMEgZAwgY2AFA6sgmBAVieX5SUT '' SIG '' /CrhClOVWeSkoWOkYTBfMRMwEQYKCZImiZPyLGQBGRYD '' SIG '' Y29tMRkwFwYKCZImiZPyLGQBGRYJbWljcm9zb2Z0MS0w '' SIG '' KwYDVQQDEyRNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0 '' SIG '' ZSBBdXRob3JpdHmCEHmtFqFKoKWtTHNY9AcTLmUwUAYD '' SIG '' VR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC5taWNyb3Nv '' SIG '' ZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvbWljcm9zb2Z0 '' SIG '' cm9vdGNlcnQuY3JsMFQGCCsGAQUFBwEBBEgwRjBEBggr '' SIG '' BgEFBQcwAoY4aHR0cDovL3d3dy5taWNyb3NvZnQuY29t '' SIG '' L3BraS9jZXJ0cy9NaWNyb3NvZnRSb290Q2VydC5jcnQw '' SIG '' EwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZIhvcNAQEF '' SIG '' BQADggIBABCXisNcA0Q23em0rXfbznlRTQGxLnRxW20M '' SIG '' E6vOvnuPuC7UEqKMbWK4VwLLTiATUJndekDiV7uvWJoc '' SIG '' 4R0Bhqy7ePKL0Ow7Ae7ivo8KBciNSOLwUxXdT6uS5OeN '' SIG '' atWAweaU8gYvhQPpkSokInD79vzkeJkuDfcH4nC8GE6d '' SIG '' jmsKcpW4oTmcZy3FUQ7qYlw/FpiLID/iBxoy+cwxSnYx '' SIG '' PStyC8jqcD3/hQoT38IKYY7w17gX606Lf8U1K16jv+u8 '' SIG '' fQtCe9RTciHuMMq7eGVcWwEXChQO0toUmPU8uWZYsy0v '' SIG '' 5/mFhsxRVuidcJRsrDlM1PZ5v6oYemIp76KbKTQGdxpi '' SIG '' yT0ebR+C8AvHLLvPQ7Pl+ex9teOkqHQ1uE7FcSMSJnYL '' SIG '' PFKMcVpGQxS8s7OwTWfIn0L/gHkhgJ4VMGboQhJeGsie '' SIG '' IiHQQ+kr6bv0SMws1NgygEwmKkgkX1rqVu+m3pmdyjpv '' SIG '' vYEndAYR7nYhv5uCwSdUtrFqPYmhdmG0bqETpr+qR/AS '' SIG '' b/2KMmyy/t9RyIwjyWa9nR2HEmQCPS2vWY+45CHltbDK '' SIG '' Y7R4VAXUQS5QrJSwpXirs6CWdRrZkocTdSIvMqgIbqBb '' SIG '' jCW/oO+EyiHW6x5PyZruSeD3AWVviQt9yGnI5m7qp5fO '' SIG '' MSn/DsVbXNhNG6HY+i+ePy5VFmvJE6P9MYIENjCCBDIC '' SIG '' AQEwLTAfMR0wGwYDVQQDExRNU0lUIEVudGVycHJpc2Ug '' SIG '' Q0EgMQIKaoENdwACAPSq3zAJBgUrDgMCGgUAoIG8MBkG '' SIG '' CSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQB '' SIG '' gjcCAQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJ '' SIG '' BDEWBBSzj4qPVYslD5+t2FoxFN+8C1jN5DBcBgorBgEE '' SIG '' AYI3AgEMMU4wTKAygDAATQBTAEkAVAAgAE8AZgBmAGkA '' SIG '' YwBlACAAMgAwADEAMwAgAHMAYwByAGkAcAB0ACChFoAU '' SIG '' aHR0cDovL2l0d2ViL29mZmljZSAwDQYJKoZIhvcNAQEB '' SIG '' BQAEggEAaOcjRQBpoQWeUCWqUgJ3UgzzVJF3mVOgfvl2 '' SIG '' WMRGXWNVhtnkH8yWyzc/ExMPgi93z7xM/tE2NDvvrcgp '' SIG '' HuwZ2d9XEvEymSWwrSrfsUhOcDrUQI2Fve7KKx56Ejol '' SIG '' Kbz9Gl/9kb3kICunoppT1+mmQS1+uIdZQZOEjedxGhhW '' SIG '' HbnIqCOMer4dAkLqZWS/4R2Y8si+rp52Yt7jHYe11LxK '' SIG '' MDdEvuErtZhsYdpRjuRCurNdWx9OBRmh1rk8yJrAuEdy '' SIG '' pK7XSe0CTwRJMrBjrM0qI4Ldr5f93uuxKLijW9/nbLVP '' SIG '' kjUUJPOZPW3tzD32Vxmi8WK3NzjscTUYSRfd1lz77qGC '' SIG '' Ah8wggIbBgkqhkiG9w0BCQYxggIMMIICCAIBATCBhTB3 '' SIG '' MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv '' SIG '' bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj '' SIG '' cm9zb2Z0IENvcnBvcmF0aW9uMSEwHwYDVQQDExhNaWNy '' SIG '' b3NvZnQgVGltZS1TdGFtcCBQQ0ECCmECkkoAAAAAACAw '' SIG '' CQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG '' SIG '' 9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTEyMTAwMjIwMDIx '' SIG '' MFowIwYJKoZIhvcNAQkEMRYEFEuqqRDOGRl0QFvGpERc '' SIG '' Emsy0oB2MA0GCSqGSIb3DQEBBQUABIIBAHFG8Os5MsQl '' SIG '' oO0QjU6V3v3vDxUpq8LWT3To8FNeQpAMEvSPz3tr81Ya '' SIG '' DhVkFVg3v90aVIub+aXkLUGuTXijsJ0dVU0TV53uaqZU '' SIG '' lJ8ie0tlVyIL+SrvXYP7kdiMt/z8p28E2UfHNp1417KU '' SIG '' kyxspSTn1r/UkzKA/LOPuqEPjccpovhZBk0uaqDPje4y '' SIG '' RA6ClhsdNvcj0YhGO9bp6t3KoHssBZfYECXQfGkXW+Fq '' SIG '' FEXTKpoVXQmSBnMRvIVcAi/D0lEl1MLc/NjCxw+Vel52 '' SIG '' m7IRQaNhaQ1fm13rVkZrlCU3GQnIGoKtvCCc1sBknv9o '' SIG '' SvI1nuVJ/5rkGH3cx34HXzI= '' SIG '' End signature block