OffScrub O16msi - Vbs
OffScrub O16msi - Vbs
OffScrub O16msi - Vbs
=====================
' Name: OffScrub_O16msi.vbs
' Author: Microsoft Customer Support Services
' Copyright (c) 2015 Microsoft Corporation
' Script to remove (scrub) Office 2016 MSI products
' when a regular uninstall is no longer possible
'==================================================================================
=====================
Option Explicit
Dim sDefault
'==================================================================================
=====================
'[INI] Section for script behavior customizations
'==================================================================================
=====================
Dim oFso, oMsi, oReg, oWShell, oWmiLocal, oShellApp
Dim ComputerItem, Item, LogStream, TmpKey
Dim arrTmpSKUs, arrDeleteFiles, arrDeleteFolders, arrMseFolders, arrVersion
Dim dicKeepProd, dicKeepLis, dicApps, dicKeepFolder, dicDelRegKey, dicKeepReg
Dim dicInstalledSku, dicRemoveSku, dicKeepSku, dicSrv, dicCSuite, dicCSingle
Dim f64, fLegacyProductFound, fCScript
Dim sTmp, sSkuRemoveList, sWinDir, sWICacheDir, sMode
Dim sAppData, sTemp, sScrubDir, sProgramFiles, sProgramFilesX86,
sCommonProgramFiles
Dim sAllusersProfile, sOSinfo, sOSVersion, sCommonProgramFilesX86,
sProfilesDirectory
Dim sProgramData, sLocalAppData, sOInstallRoot, sScriptDir, sNotepad
Dim iVersionNT, iError
'==================================================================================
=====================
'Main
'==================================================================================
=====================
'Configure defaults
Dim sLogDir : sLogDir = ""
Dim sMoveMessage: sMoveMessage = ""
Dim fClearAddinReg : fClearAddinReg = False
Dim fRemoveOse : fRemoveOse = False
Dim fRemoveOspp : fRemoveOspp = False
Dim fRemoveAll : fRemoveAll = False
Dim fRemoveC2R : fRemoveC2R = False
Dim fRemoveAppV : fRemoveAppV = False
Dim fRemoveCSuites : fRemoveCSuites = False
Dim fRemoveCSingle : fRemoveCSingle = False
Dim fRemoveSrv : fRemoveSrv = False
Dim fRemoveLync : fRemoveLync = False
Dim fKeepUser : fKeepUser = True 'Default to keep per user settings
Dim fSkipSD : fSkipSD = False 'Default to not Skip the Shortcut Detection
Dim fKeepSG : fKeepSG = False 'Default to not override the SoftGrid
detection
Dim fDetectOnly : fDetectOnly = False
Dim fQuiet : fQuiet = False
Dim fBasic : fBasic = False
Dim fNoCancel : fNoCancel = False
Dim fPassive : fPassive = True
Dim fNoReboot : fNoReboot = False 'Default to offer reboot prompt if needed
Dim fNoElevate : fNoElevate = False
Dim fElevated : fElevated = False
Dim fTryReconcile : fTryReconcile = False
Dim fC2rInstalled : fC2rInstalled = False
Dim fRebootRequired : fRebootRequired = False
Dim fReturnErrorOrSuccess : fReturnErrorOrSuccess = False
Dim fEndCurrentInstalls : fEndCurrentInstalls = False
'CAUTION! -> "fForce" will kill running applications which can result in data loss!
<- CAUTION
Dim fForce : fForce = False
'CAUTION! -> "fForce" will kill running applications which can result in data loss!
<- CAUTION
Dim fLogInitialized : fLogInitialized = False
Dim fBypass_Stage1 : fBypass_Stage1 = True 'Component Detection
Dim fBypass_Stage2 : fBypass_Stage2 = False 'Setup
Dim fBypass_Stage3 : fBypass_Stage3 = False 'Msiexec
Dim fBypass_Stage4 : fBypass_Stage4 = False 'CleanUp
sCommonProgramFiles = oWShell.ExpandEnvironmentStrings("%commonprogramfiles%")
'Deferred until after architecture check
'sCommonProgramFilesX86 =
oWShell.ExpandEnvironmentStrings("%CommonProgramFiles(x86)%")
sProgramData = oWSHell.ExpandEnvironmentStrings("%programdata%")
sWinDir = oWShell.ExpandEnvironmentStrings("%windir%")
sWICacheDir = sWinDir & "\" & "Installer"
sScrubDir = sTemp & "\" & SCRIPTNAME
sNotepad = sWinDir & "\notepad.exe"
'sScriptDir only required for OSPP cleanup
sScriptDir = wscript.ScriptFullName
sScriptDir = Left(sScriptDir, InStrRev(sScriptDir, "\"))
fElevated = CheckRegPermissions
If NOT fElevated AND NOT fNoElevate Then
'Try to relaunch elevated
RelaunchElevated
'-------------------
'Stage # 0 - Basics |
'-------------------
'Build a list with installed/registered Office products
sTmp = "Stage # 0 " & chr(34) & "Basics" & chr(34) & " (" & Time & ")"
LogH2 vbCrLf & sTmp & vbCrLf & String(Len(sTmp),"=") & vbCrLf
FindInstalledOProducts
If dicInstalledSku.Count > 0 Then Log "Found registered product(s): " &
Join(RemoveDuplicates(dicInstalledSku.Items),",")
'Validate the list of products we got from the command line if applicable
ValidateRemoveSkuList
'UnPin Shortcuts
If NOT fSkipSD AND dicRemoveSku.Count > 0 Then
On Error Resume Next
LogH1 "UnPin shortcuts"
CleanShortcuts sAllUsersProfile, False, True
CleanShortcuts sProfilesDirectory, False, True
On Error Goto 0
End If 'NOT SkipSD
'--------------------------------
'Stage # 1 - Component Detection |
'--------------------------------
sTmp = "Stage # 1 " & chr(34) & "Component Detection" & chr(34) & " (" & Time & ")"
LogH2 vbCrLf & sTmp & vbCrLf & String(Len(sTmp),"=") & vbCrLf
If Not fBypass_Stage1 OR fForce Then
'Build a list with files which are installed/registered to a product that's
going to be removed
Log "Prepare for CleanUp stages."
Log "Identifying removable elements. This can take several minutes."
ScanComponents
Else
Log "Not running Component Detection in default removal."
End If
'----------------------
'Stage # 2 - Setup.exe |
'----------------------
sTmp = "Stage # 2 " & chr(34) & "Setup.exe" & chr(34) & " (" & Time & ")"
LogH2 vbCrLf & sTmp & vbCrLf & String(Len(sTmp),"=") & vbCrLf
If Not fBypass_Stage2 Then
SetupExeRemoval
Else
Log "Skipping Setup.exe because bypass was requested."
End If
'------------------------
'Stage # 3 - Msiexec.exe |
'------------------------
sTmp = "Stage # 3 " & chr(34) & "Msiexec.exe" & chr(34) & " (" & Time & ")"
LogH2 vbCrLf & sTmp & vbCrLf & String(Len(sTmp),"=") & vbCrLf
If Not fBypass_Stage3 Then
MsiexecRemoval
Else
Log "Skipping Msiexec.exe because bypass was requested."
End If
'--------------------
'Stage # 4 - CleanUp |
'--------------------
'Removal of files and registry settings
sTmp = "Stage # 4 " & chr(34) & "CleanUp" & chr(34) & " (" & Time & ")"
LogH2 vbCrLf & sTmp & vbCrLf & String(Len(sTmp),"=") & vbCrLf
If Not fBypass_Stage4 Then
'Obsolete files
LogH1 "File CleanUp"
If fRemoveAll Then
FileWipeAll
Else
FileWipeIndividual
End If
'Empty Folders
LogH1 "Folder CleanUp"
DeleteEmptyFolders
'Registry data
LogH1 "Registry CleanUp"
RegWipe
'Temporary files
DelScrubTmp
Else
Log "Skipping CleanUp because bypass was requested."
End If
If Not sMoveMessage = "" Then Log vbCrLf & "Please remove this folder after next
reboot: " & sMoveMessage
ExitScript
'-------------------------------------------------------------------------------
' ExitScript
'
' Returncode and reboot handler
'-------------------------------------------------------------------------------
Sub ExitScript
Dim sPrompt
sTmp = "ReturnErrorOrSuccess switch has been set. The current value return
code translates to: "
If fOverallSuccess Then
iError = ERROR_SUCCESS
Log sTmp & "SUCCESS"
Else
Log sTmp & "ERROR"
End If
End If
wscript.quit iError
End Sub 'ExitScript
'==================================================================================
=====================
'==================================================================================
=====================
'Stage 0 - 4 Subroutines
'==================================================================================
=====================
'Office configuration products are listed with their configuration product name in
the "Uninstall" key
'To identify an Office configuration product all of these condiditions have to be
met:
' - "SystemComponent" does not have a value of "1" (DWORD)
' - "OPACKAGE" (see constant declaration) entry exists and is not empty
' - "DisplayVersion" exists and the 2 leftmost digits are "OVERSIONMAJOR"
Sub FindInstalledOProducts
Dim ArpItem, File
Dim sCurKey, sValue, sConfigName, sProdC, sCVHValue
Dim sProductCodeList, sProductCode
Dim arrKeys, arrMultiSzValues
Dim fSystemComponent0, fPackages, fDisplayVersion, fReturn, fCategorized
If dicInstalledSku.Count > 0 Then Exit Sub 'Already done from InputBox prompt
'Locate standalone Office products that have no configuration product entry and
create a
'temporary configuration entry
ReDim arrTmpSKUs(-1)
If RegEnumKey(HKLM,REG_ARP,arrKeys) Then
For Each ArpItem in arrKeys
If InScope(ArpItem) Then
sCurKey = REG_ARP & ArpItem & "\"
fSystemComponent0 = Not
(RegReadValue(HKLM,sCurKey,"SystemComponent",sValue,"REG_DWORD") AND (sValue =
"1"))
If (fSystemComponent0 AND (NOT
RegReadValue(HKLM,sCurKey,"CVH",sCVHValue,"REG_DWORD"))) Then
RegReadValue HKLM,sCurKey,"DisplayVersion",sValue,"REG_SZ"
Redim arrMultiSzValues(0)
'Logic changed to drop the LCID identifier
'sConfigName = GetProductID(Mid(ArpItem,11,4)) & "_" &
CInt("&h" & Mid(ArpItem,16,4))
sConfigName = OREGREF & GetProductID(Mid(ArpItem,11,4))
If NOT RegKeyExists(HKLM,REG_ARP&sConfigName) Then
'Create a new ARP item
ReDim Preserve arrTmpSKUs(UBound(arrTmpSKUs)+1)
arrTmpSKUs(UBound(arrTmpSKUs)) = sConfigName
oReg.CreateKey HKLM,REG_ARP & sConfigName
arrMultiSzValues(0) = sConfigName
oReg.SetMultiStringValue HKLM,REG_ARP &
sConfigName,OPACKAGE,arrMultiSzValues
arrMultiSzValues(0) = ArpItem
oReg.SetStringValue HKLM, REG_ARP & sConfigName, "Comment",
"Temporary OffScrub generated key. Please delete this key!"
oReg.SetMultiStringValue HKLM,REG_ARP &
sConfigName,"ProductCodes",arrMultiSzValues
oReg.SetStringValue HKLM,REG_ARP &
sConfigName,"DisplayVersion",sValue
oReg.SetStringValue HKLM,REG_ARP &
sConfigName,"DisplayName",SCRIPTNAME & "_" & sConfigName
oReg.SetDWordValue HKLM,REG_ARP &
sConfigName,"SystemComponent",0
Else
'Update the existing temporary ARP item
fReturn =
RegReadValue(HKLM,REG_ARP&sConfigName,"ProductCodes",sProdC,"REG_MULTI_SZ")
If NOT InStr(sProdC,ArpItem)>0 Then sProdC = sProdC &
chr(34) & ArpItem
oReg.SetMultiStringValue HKLM,REG_ARP &
sConfigName,"ProductCodes",Split(sProdC,chr(34))
End If 'RegKeyExists
End If 'fSystemComponent0
End If 'InScope
Next 'ArpItem
End If 'RegEnumKey
End If 'Len 38
Next 'sProductCode
If NOT fCategorized Then
If NOT dicCSingle.Exists(UCase(sConfigName)) Then
dicCSingle.Add UCase(sConfigName),sConfigName
End If 'fCategorized
End If 'RegReadValue "ProductCodes"
End If
Next 'ArpItem
End If 'RegEnumKey
End Sub 'FindInstalledOProducts
'==================================================================================
=====================
'Check if there are Office products from previous versions on the computer
Sub CheckForLegacyProducts
Const OLEGACY = "78E1-11D2-B60F-006097C998E7}.6000-11D3-8CFE-
0050048383C9}.6000-11D3-8CFE-0150048383C9}.BDCA-11D1-B7AE-00C04FB92F3D}.6D54-11D4-
BEE3-00C04F990354}"
Dim Product
If fRemoveAll Then
'Remove all mode
For Each Key in dicInstalledSku.Keys
dicRemoveSku.Add Key,dicInstalledSku.Item(Key)
Next 'Key
Else
'Remove individual products or preconfigured configurations mode
'Server Category
If fRemoveSrv Then
For Each Key in dicInstalledSku.Keys
If dicSrv.Exists(Key) Then
If dicKeepSku.Exists(Key) Then dicKeepSku.Remove(Key)
If NOT dicRemoveSku.Exists(Key) Then dicRemoveSku.Add Key,Key
End If
Next 'Key
End If 'fRemoveSrv
End If 'fRemoveAll
If fC2rInstalled Then
fRemoveOspp = False
Exit Sub
End If
'Cache .msi files for products that will be removed in case they are needed for
later file detection
Sub CacheMsiFiles
Dim Product
Dim sMsiFile
Err.Clear
End Sub 'CacheMsiFiles
'==================================================================================
=====================
'Logfile
Set FileList = oFso.OpenTextFile(sScrubDir & "\
FileList.txt",FOR_WRITING,True,True)
Set RegList = oFso.OpenTextFile(sScrubDir & "\
RegList.txt",FOR_WRITING,True,True)
Set CompVerbose = oFso.OpenTextFile(sScrubDir & "\
CompVerbose.txt",FOR_WRITING,True,True)
'FileListError dic
Set dicFLError = CreateObject("Scripting.Dictionary")
iCompCnt = oMsi.Components.Count
If NOT Err = 0 Then
'API failure
Log "Error during components detection. Cannot complete this task."
Err.Clear
Exit Sub
End If
'Progress bar
i = i + 1
If iProgress < (i / iCompCnt) * 100 Then
If fCScript Then wscript.stdout.write "." : LogStream.Write "."
iProgress = iProgress + 1
If iProgress = 35 OR iProgress = 70 Then Log ""
End If
If fRemoveComponent Then
CompVerbose.WriteLine " RESULT: Component IN SCOPE for removal"
fIsFile = False : fIsFolder = False
'Go for the safe way and just reset the default entry
'compared to deleting the whole key
If Right(sPath,1) = "\" Then sPath = sPath & "(Default)"
'File or Folder
If oFso.FileExists(sPath) OR oFso.FolderExists(sPath) Then
If Right(sPath,1) = "\" Then
fIsFolder = True
CompVerbose.WriteLine " Folder check OK"
Else
fIsFile = True
CompVerbose.WriteLine " File check OK"
End If
If fIsFile Then sPath = oFso.GetFile(sPath).ParentFolder
If Not oFolderDic.Exists(sPath) Then
oFolderDic.Add sPath,sPath
FileList.WriteLine sPath & vbTab & "(FOLDER)"
End If
'Get the .msi file
If oFso.FileExists(sScrubDir & "\" & sCompClient & ".msi")
Then
sMsiFile = sScrubDir & "\" & sCompClient & ".msi"
Else
sMsiFile = oMsi.ProductInfo(sCompClient,"LocalPackage")
End If
CompVerbose.WriteLine " Set msi file to : " & sMsiFile
If Not Err = 0 Then
CompVerbose.WriteLine " Error: Failed to obtain .msi
file for product " & sCompClient
If NOT dicFLError.Exists("Failed to obtain .msi file
for product "&sCompClient) Then _
dicFLError.Add "Failed to obtain .msi file for
product "&sCompClient, ComponentID
Err.Clear
End If
CompVerbose.Write " Open .msi file for reading returned: "
Set MsiDb =
oMsi.OpenDatabase(sMsiFile,MSIOPENDATABASEREADONLY)
If Err = 0 Then
CompVerbose.WriteLine " SUCCESS"
'Get the component name from the 'Component' table
sQuery = "SELECT `Component`,`ComponentId` FROM
Component WHERE `ComponentId` = '" & ComponentID &"'"
Set qView = MsiDb.OpenView(sQuery) : qView.Execute
Set Record = qView.Fetch()
If Not Record Is Nothing Then sComponent =
Record.Stringdata(1)
CompVerbose.WriteLine " Obtained ComponentId as: " &
sComponent
iSetupCnt = 0
If Not dicRemoveSku.Count > 0 Then
Log " Nothing to remove for Setup.exe"
Exit Sub
End If
'Ensure that the OSE service is *installed, *not disabled, *running under
System context.
'If validation fails exit out of this sub.
Set OseService = oWmiLocal.Execquery("Select * From Win32_Service Where Name
like 'ose%'")
If OseService.Count = 0 Then Exit Sub
For Each Service in OseService
If (Service.StartMode = "Disabled") AND (Not
Service.ChangeStartMode("Manual")=0) Then Exit Sub
If (Not Service.StartName = "LocalSystem") AND (Service.Change( , , , , , ,
"LocalSystem", "")) Then Exit Sub
Next 'Service
Dim Product
Dim i
Dim sCmd, sReturn, sMsiProp
Dim fRegWipe
fRegWipe = False
'MSECache
If EnumFolders(sProgramFiles,arrSubFolders) Then
For Each SubFolder in arrSubFolders
If UCase(Right(SubFolder,9))="\MSECACHE" Then
ReDim arrMseFolders(-1)
Set Folder = oFso.GetFolder(SubFolder)
GetMseFolderStructure Folder
For Each MseFolder in arrMseFolders
If oFso.FolderExists(MseFolder) Then
fRemoveFolder = False
Set Folder = oFso.GetFolder(MseFolder)
Set Files = Folder.Files
For Each File in Files
If (LCase(Right(File.Name,4))=".msi") Then
If CheckDelete(ProductCode(File.Path)) Then
fRemoveFolder = True
Exit For
End If 'CheckDelete
End If
Next 'File
Set Files = Nothing
Set Folder = Nothing
If fRemoveFolder Then SmartDeleteFolder MseFolder
End If 'oFso.FolderExists(MseFolder)
Next 'MseFolder
End If
Next 'SubFolder
End If 'oFso.FolderExists
End Sub 'WipeLis
'==================================================================================
=====================
'Wipe individual files & folders related to SKU's that are no longer installed
Sub FileWipeIndividual
Dim LogicalDisks, Disk,sc
Dim File, Files, XmlFile, scFiles, oFile, Folder, SubFolder, Processes,
Process, item
Dim sFile, sFolder, sPath, sConfigName, sContents, sProductCode,
sLocalDrives,sScQuery
Dim sValue, sScRoots
Dim arrSubfolders, arrShortCutRoots
Dim fKeepFolder, fDeleteSC
Dim iRet,iCnt,iPos
'Wipe Shortcuts
If NOT fSkipSD Then
On Error Resume Next
LogH2 "Shortcuts"
CleanShortcuts sAllUsersProfile, True, False
CleanShortcuts sProfilesDirectory, True, False
On Error Goto 0
End If 'NOT SkipSD
Err.Clear
'-------------------------------------------------------------------------------
' CleanShortcuts
'
' Recursively search all profile folders for Office shortcuts in scope
'-------------------------------------------------------------------------------
Sub CleanShortcuts (sFolder, fDelete, fUnPin)
Dim oFolder, fld, file, sc, item
Dim fDeleteSC
'-------------------------------------------------------------------------------
' UnPin
'
' Unpins a shortcut from the taskbar or start menu
'-------------------------------------------------------------------------------
Sub UnPin(file)
Dim fldItem, verb
Sub DelScrubTmp
Sub MsiClearOrphanedFiles
Const USERSIDEVERYONE = "s-1-1-0"
Const MSIINSTALLCONTEXT_ALL = 7
Const MSIPATCHSTATE_ALL = 15
Sub RegWipe
Dim Item, Name, Sku, key
Dim hDefKey, sSubKeyName, sCurKey, value, sValue, sGuid
Dim fkeep, fSystemComponent0, fPackages, fDisplayVersion
Dim arrKeys, arrNames, arrTypes, arrMultiSzValues, arrMultiSzNewValues
Dim arrTestNames, arrTestTypes
Dim i, iLoopCnt, iPos
Dim fDelReg
Case 15
Case 16
Case Else
End Select
'Win32Assemblies
LogH2 "Win32Assemblies"
If RegEnumKey(HKCR,"Installer\Win32Assemblies\",arrKeys) Then
For Each Item in arrKeys
If InStr(UCase(Item),OREF)>0 Then RegDeleteKey HKCR,"Installer\
Win32Assemblies\"&Item & "\"
Next 'Item
End If 'RegEnumKey
'Groove blocks reinstall if it locates groove.exe over this key
If RegKeyExists(HKCR,"GrooveFile\Shell\Open\Command\") Then
sValue = ""
RegReadValue HKCR,"GrooveFile\Shell\Open\Command\","",sValue,"REG_SZ"
If InStr(sValue,"\"&OREF&"\")>0 Then RegDeleteKey HKCR,"GrooveFile\"
End If 'RegKeyExists
End If 'fRemoveAll
If RegEnumKey(hDefKey,sSubKeyName,arrKeys) Then
For Each Item in arrKeys
'OFFICEID id
If Len(Item)>37 Then
sGuid = UCase(Left(Item,38))
If Right(sGuid,PRODLEN)=OFFICEID Then
If CheckDelete(sGuid) Then
RegDeleteKey hDefKey, sSubKeyName & Item & "\"
End If
End If 'Right(Item,PRODLEN)=OFFICEID
End If 'Len(Item)>37
Next 'Item
If iLoopCnt < 3 Then
If RegEnumValues(hDefKey,sSubKeyName,arrNames,arrTypes) Then
i = 0
For Each Name in arrNames
If
RegReadValue(hDefKey,sSubKeyName,Name,sValue,arrTypes(i)) Then
If sValue = sGuid Then RegDeleteValue
hDefKey,sSubKeyName,Name, False
End If
i = i + 1
Next
End If
End If
End If
If NOT RegEnumKey(hDefKey,sSubKeyName,arrKeys) Then RegDeleteKey
hDefKey,"Software\Microsoft\OfficeCustomizeWizard\11.0\"
If NOT RegEnumKey(hDefKey,"Software\Microsoft\OfficeCustomizeWizard\
11.0\",arrKeys) Then RegDeleteKey hDefKey,"Software\Microsoft\
OfficeCustomizeWizard\"
Next 'iLoopCnt
Case "12"
'Add/Remove Programs
RegWipeARP
Case "14"
'Add/Remove Programs
RegWipeARP
Case Else
End Select
'Components
Log " - Global Components"
sSubKeyName = "SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-
1-5-18\Components\"
If RegEnumKey(HKLM,sSubKeyName,arrKeys) Then
For Each Item in arrKeys
'Ensure we have the expected length for a compressed GUID
If Len(Item)=32 Then
If RegEnumValues(HKLM,sSubKeyName & Item,arrNames,arrTypes) Then
If IsArray(arrNames) Then
For Each Name in arrNames
If Len(Name)=32 Then
sGuid = GetExpandedGuid(Name)
If CheckDelete(sGuid) Then
RegDeleteValue HKLM, sSubKeyName & Item & "\",
Name, False
'Check if the key is now empty
If NOT RegEnumValues(HKLM,sSubKeyName &
Item,arrTestNames,arrTestTypes) Then
If NOT
dicDelRegKey.Exists(sSubKeyName&Item&"\") Then dicDelRegKey.Add
sSubKeyName&Item&"\",HKCR
End If
End If
End If '32
Next 'Name
End If 'IsArray
End If 'RegEnumValues
End If '32
Next 'Item
End If 'RegEnumKey
'Published Components
Log " - Published Components"
sSubKeyName = "Installer\Components\"
If RegEnumKey(HKCR,sSubKeyName,arrKeys) Then
For Each Item in arrKeys
'Ensure we have the expected length for a compressed GUID
If Len(Item)=32 Then
If RegEnumValues(HKCR,sSubKeyName & Item,arrNames,arrTypes) Then
If IsArray(arrNames) Then
For Each Name in arrNames
If RegReadValue (HKCR,sSubKeyName & Item, Name,
sValue,"REG_MULTI_SZ") Then
arrMultiSzValues = Split(sValue,chr(34))
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 fDetectOnly Then
If NOT UBound(arrMultiSzValues) = i
Then oReg.SetMultiStringValue HKCR,sSubKeyName & Item,Name,arrMultiSzNewValues
End If
Else
If fDelReg Then
RegDeleteValue HKCR,sSubKeyName & Item
& "\", Name, False
'Check if the key is now empty
If NOT RegEnumValues(HKCR,sSubKeyName &
Item,arrTestNames,arrTestTypes) Then
If NOT
dicDelRegKey.Exists(sSubKeyName&Item&"\") Then dicDelRegKey.Add
sSubKeyName&Item&"\",HKCR
End If
End If 'DelReg
End If
End If 'IsArray
End If
Next 'Name
End If 'IsArray
End If 'RegEnumValues
End If '32
Next 'Item
End If 'RegEnumKey
'Delivery
Log " - Delivery"
hDefKey = HKLM
sSubKeyName = "SOFTWARE\Microsoft\Office\Delivery\SourceEngine\Downloads\"
If RegEnumKey(HKLM,sSubKeyName,arrKeys) Then
For Each Item in arrKeys
If Len(Item) > 37 Then
If fRemoveAll Then
If (Mid(Item,27,PRODLEN)=OFFICEID AND
Mid(Item,4,2)=OVERSIONMAJOR) OR _
LCase(Right(Item,7))=OVERSIONMAJOR&".data" Then RegDeleteKey
HKLM,sSubKeyName & Item & "\"
Else
If (Mid(Item,27,PRODLEN)=OFFICEID AND
Mid(Item,4,2)=OVERSIONMAJOR) AND _
CheckDelete(UCase(Left(Item,38))) Then RegDeleteKey
HKLM,sSubKeyName & Item & "\"
End If
End If '37
Next 'Item
End If 'RegEnumKey
'Registration
Log " - HKLM Registration"
hDefKey = HKLM
sSubKeyName = "SOFTWARE\Microsoft\Office\"&OVERSION&"\Registration\"
If RegEnumKey(HKLM,sSubKeyName,arrKeys) Then
For Each Item in arrKeys
If Len(Item)>37 Then
If CheckDelete(UCase(Left(Item,38))) Then RegDeleteKey
HKLM,sSubKeyName & Item & "\"
End If
Next 'Item
End If 'RegEnumKey
'User Preconfigurations
Log " - HKLM User Preconfigurations"
hDefKey = HKLM
sSubKeyName = "SOFTWARE\Microsoft\Office\"&OVERSION&"\User Settings\"
If RegEnumKey(HKLM,sSubKeyName,arrKeys) Then
For Each Item in arrKeys
If Len(Item)>37 Then
If CheckDelete(UCase(Left(Item,38))) Then RegDeleteKey
HKLM,sSubKeyName & Item & "\"
End If
Next 'Item
End If 'RegEnumKey
'Add/Remove Programs
sSubKeyName = REG_ARP
If RegEnumKey(HKLM,sSubKeyName,arrKeys) Then
For Each Item in arrKeys
'*0FF1CE*
If Len(Item) > 37 Then
sGuid = UCase(Left(Item, 38))
If CheckDeleteEx(sGuid) Then RegDeleteKey HKLM, sSubKeyName & Item
End If 'Len(Item)>37
'Config entries
sCurKey = sSubKeyName & Item & "\"
fSystemComponent0 = Not (RegReadValue(HKLM, sCurKey, "SystemComponent",
sValue, "REG_DWORD") AND (sValue = "1"))
fPackages = RegReadValue(HKLM,sCurKey,OPACKAGE,sValue,"REG_MULTI_SZ")
fDisplayVersion = RegReadValue(HKLM, sCurKey, "DisplayVersion", sValue,
"REG_SZ")
If fDisplayVersion AND Len(sValue) > 1 Then
fDisplayVersion = (Left(sValue, 2) = OVERSIONMAJOR)
End If
If (fPackages AND fDisplayVersion) Then
fKeep = False
If Not fRemoveAll Then
For Each Sku in dicKeepSku.Keys
If UCase(Item) = OREGREF & Sku Then
fkeep = True
Exit For
End If
Next 'Sku
End If
If Not fkeep Then RegDeleteKey HKLM, sSubKeyName & Item
End If
Next 'Item
End If 'RegEnumKey
'==================================================================================
=====================
' Helper Functions
'==================================================================================
=====================
SkuLog.Close
Set SkuLog = Nothing
fWait = False
Log " Doing Action: CloseOfficeApps"
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
CheckDeleteEx = False
If CheckDelete (sProductCode) Then
CheckDeleteEx = True
Exit Function
End If
If (fRemoveAll AND NOT fC2rInstalled) OR (fRemoveAll AND fForce) Then
CheckDeleteEx = InScope(sProductCode) AND NOT
dicKeepProd.Exists(UCase(sProductCode))
End If
End Function 'CheckDelete
'==================================================================================
=====================
'Check if an Office product is still registered with a SKU that stays on the
computer
Function CheckDelete (sProductCode)
'If it's a non Office ProductCode exit with false right away
CheckDelete = InScope(sProductCode)
If Not CheckDelete Then Exit Function
If dicKeepProd.Exists(UCase(sProductCode)) Then CheckDelete = False
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 fInScope = True
Case "12"
If Right(sProd, PRODLEN) = OFFICEID AND Mid(sProd, 4, 2) =
OVERSIONMAJOR Then fInScope = True
Case "14"
If Right(sProd, PRODLEN) = OFFICEID AND Mid(sProd, 4, 2) =
OVERSIONMAJOR Then fInScope = True
Case "15", "16"
If Right(sProd, PRODLEN) = OFFICEID AND Mid(sProd, 4, 2) =
OVERSIONMAJOR Then
Select Case Mid(sProd, 11, 4)
Case "007E", "008F", "008C", "24E1", "237A"
' C2R products - keep them
Case Else
fInScope = True
End Select
End If
Case Else
End Select
End If '38
InScope = fInScope
End Function 'InScope
'==================================================================================
=====================
For iCnt = 1 To 3
Select Case iCnt
Case 1
sCurKey = REG_ARP & sProductCode
oReg.CreateKey HKLM,sCurKey
Case 2
sCurKey = "SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\
UserData\S-1-5-18\Products\" & GetCompressedGuid(sProductCode)
oReg.CreateKey HKLM,sCurKey
oReg.CreateKey HKLM,sCurKey & "\Features"
oReg.CreateKey HKLM,sCurKey & "\InstallProperties"
oReg.CreateKey HKLM,sCurKey & "\Patches"
oReg.CreateKey HKLM,sCurKey & "\Usage"
sCurKey = sCurKey & "\InstallProperties"
oReg.SetStringValue HKLM,sCurKey,"LocalPackage",sMsiFile
Case 3
sCurKey = "Installer\Products\" & GetCompressedGuid(sProductCode)
sTmpKey = sCurKey
oReg.CreateKey HKCR,sCurKey
oReg.SetDWordValue HKCR,sCurKey,"AdvertiseFlags",388
oReg.SetDWordValue HKCR,sCurKey,"Assignment",1
oReg.SetDWordValue HKCR,sCurKey,"AuthorizedLUAApp",0
oReg.SetStringValue HKCR,sCurKey,"Clients",":"
oReg.SetDWordValue HKCR,sCurKey,"DeploymentFlags",3
oReg.SetDWordValue HKCR,sCurKey,"InstanceType",0
oReg.SetDWordValue HKCR,sCurKey,"Language",sLang
oReg.SetStringValue
HKCR,sCurKey,"PackageCode",GetMsiPackageCode(sMsiFile)
oReg.SetStringValue HKCR,sCurKey,"ProductName",sDisplayName
oReg.SetDWordValue HKCR,sCurKey,"VersionMinor",0
sCurKey = sTmpKey & "\SourceList"
oReg.CreateKey HKCR,sCurKey
oReg.SetExpandedStringValue HKCR,sCurKey,"LastUsedSource",sScrubDir
oReg.SetStringValue
HKCR,sCurKey,"PackageName",Mid(sMsiFile,InstrRev(sMsiFile,"\")+1)
sCurKey = sTmpKey & "\SourceList\Media"
oReg.CreateKey HKCR,sCurKey
oReg.SetStringValue HKCR,sCurKey,"1",OREF & ";1"
oReg.SetStringValue HKCR,sCurKey,"DiskPrompt",sDisplayName
sCurKey = sTmpKey & "\SourceList\Net"
oReg.CreateKey HKCR,sCurKey
oReg.SetExpandedStringValue HKCR,sCurKey,"1",sScrubDir
Case Else
End Select
If iCnt <3 Then
oReg.SetStringValue HKLM,sCurKey,"Comments",""
oReg.SetStringValue HKLM,sCurKey,"Contact",""
oReg.SetStringValue HKLM,sCurKey,"DisplayName",sDisplayName
oReg.SetStringValue HKLM,sCurKey,"DisplayVersion",sDisplayVersion
oReg.SetDWordValue HKLM,sCurKey,"EstimatedSize",0
oReg.SetStringValue HKLM,sCurKey,"HelpLink",""
oReg.SetStringValue HKLM,sCurKey,"HelpTelephone",""
oReg.SetStringValue HKLM,sCurKey,"InstallDate","20100101"
If f64 Then
oReg.SetStringValue HKLM,sCurKey,"InstallLocation",sProgramFilesX86
Else
oReg.SetStringValue HKLM,sCurKey,"InstallLocation",sProgramFiles
End If
oReg.SetStringValue HKLM,sCurKey,"InstallSource",sScrubDir
oReg.SetDWordValue HKLM,sCurKey,"Language",sLang
oReg.SetExpandedStringValue HKLM,sCurKey,"ModifyPath","MsiExec.exe /X"
& sProductCode
oReg.SetDWordValue HKLM,sCurKey,"NoModify",1
oReg.SetStringValue HKLM,sCurKey,"Publisher","Microsoft Corporation"
oReg.SetStringValue HKLM,sCurKey,"Readme",""
oReg.SetStringValue HKLM,sCurKey,"Size",""
oReg.SetDWordValue HKLM,sCurKey,"SystemComponent",0
oReg.SetExpandedStringValue HKLM,sCurKey,"UninstallString","MsiExec.exe
/X" & sProductCode
oReg.SetStringValue HKLM,sCurKey,"URLInfoAbout",""
oReg.SetStringValue HKLM,sCurKey,"URLUpdateInfo",""
oReg.SetDWordValue HKLM,sCurKey,"Version",0
oReg.SetDWordValue HKLM,sCurKey,"VersionMajor",OVERSIONMAJOR
oReg.SetDWordValue HKLM,sCurKey,"VersionMinor",0
oReg.SetDWordValue HKLM,sCurKey,"WindowsInstaller",1
End If '< 3
Next 'iCnt
Dim MsiDb,Record
Dim qView
Dim MsiDb,Record
Dim qView
GetMsiProductVersion = ""
Set Record = Nothing
Dim MsiDb,Record
Dim qView
GetMsiProductName = ""
Set Record = Nothing
Const PID_REVNUMBER = 9
GetMsiPackageCode = ""
GetMsiPackageCode =
GetCompressedGuid(oMsi.SummaryInformation(sMsiFile,MSIOPENDATABASEREADONLY).Propert
y(PID_REVNUMBER))
'Returns a string with a list of ProductCodes from the summary information stream
Function MspTargets (sMspFile)
Const MSIOPENDATABASEMODE_PATCHFILE = 32
Const PID_TEMPLATE = 7
Dim Msp
'Non critical routine. Don't fail on error
On Error Resume Next
MspTargets = ""
If oFso.FileExists(sMspFile) Then
Set Msp =
Msi.OpenDatabase(WScript.Arguments(0),MSIOPENDATABASEMODE_PATCHFILE)
If Err = 0 Then MspTargets = Msp.SummaryInformation.Property(PID_TEMPLATE)
End If 'oFso.FileExists(sMspFile)
End Function 'MspTargets
'==================================================================================
=====================
GetUpgradeCode = "{00" & Mid(sGuid, 4, 2) & "0000-" & Mid(sGuid, 11, 4) & "-
0000-" & Mid(sGuid, 21, 1) & "000-" & Mid(sGuid, 26, 1) & "000000FF1CE}"
'Unsquish GUID
Function GetDecodedGuid(sEncGuid, sGuid)
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) &"}"
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
'==================================================================================
=====================
'Ensures that only valid metadata entries exist to avoid API failures
Sub EnsureValidWIMetadata (hDefKey,sKey,iValidLength)
Dim arrKeys
Dim SubKey
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
'-------------------------------------------------------------------------------
' CleanOSPP
'
' Clean out licenses from the Office Software Protection Platform
'-------------------------------------------------------------------------------
Sub CleanOSPP
Dim oProductInstances, pi
Dim sCleanOSPP, sCmd, sRetVal
sCleanOSPP = "x64\CleanOSPP.exe"
If Not f64 Then sCleanOSPP = "x86\CleanOSPP.exe"
If oFso.FileExists(sScriptDir & sCleanOSPP) Then
sCmd = sScriptDir & sCleanOSPP
Log " Running: " & sCmd
On Error Resume Next
sRetVal = oWShell.Run(sCmd, 0, True)
Log " Return value: " & sRetVal
On Error Goto 0
Exit Sub
End If
If dicKeepFolder.Exists(LCase(sFile)) Then
If NOT fForce Then
LogOnly " - Disallowing the delete of still required keypath element: "
& sFile
Exit Sub
Else
LogOnly " - Enforced delete of still required keypath element: " &
sFile
LogOnly " Remaining applications will need a repair!"
End If
End If
If f64 Then
If dicKeepFolder.Exists(LCase(Wow64Folder(sFile))) Then
If NOT fForce Then
LogOnly " - Disallowing the delete of still required keypath element: "
& sFile
Exit Sub
Else
LogOnly " - Enforced delete of still required keypath element: " &
sFile
LogOnly " Remaining applications will need a repair!"
End If
End If
End If
If oFso.FileExists(sFile) Then
LogOnly " - Delete file: " & sFile
If Not fDetectOnly Then oFso.DeleteFile sFile,True
If Err <> 0 Then
CheckError "DeleteFile"
If fForce Then
'Try to move the file and delete from there
Set File = oFso.GetFile(sFile)
sFileName = File.Name
sNewPath = sScrubDir & "\ScrubTmp"
Set File = Nothing
If Not oFso.FolderExists(sNewPath) Then oFso.CreateFolder(sNewPath)
'Move the file
LogOnly " - Move file to: " & sNewPath & "\" & sFileName
oFso.MoveFile sFile,sNewPath & "\" & sFileName
If Err <> 0 Then
CheckError "DeleteFile (move)"
End If 'Err <> 0
Else
fRebootRequired = True
End If 'fForce
End If 'Err <> 0
End If 'oFso.FileExists
End Sub 'DeleteFile
'==================================================================================
=====================
If oFso.FolderExists(sFolder) Then
Set Folder = oFso.GetFolder(sFolder)
For Each Subfolder in Folder.Subfolders
sSubFolders = sSubFolders & Subfolder.Name & ","
Next 'Subfolder
End If
If f64 AND oFso.FolderExists(Wow64Folder(sFolder)) Then
Set Folder = oFso.GetFolder(Wow64Folder(sFolder))
For Each Subfolder in Folder.Subfolders
sSubFolders = sSubFolders & Subfolder.Name & ","
Next 'Subfolder
End If
If Len(sSubFolders)>0 Then arrSubFolders =
RemoveDuplicates(Split(Left(sSubFolders,Len(sSubFolders)-1),","))
EnumFolderNames = Len(sSubFolders)>0
End Function 'EnumFolderNames
'==================================================================================
=====================
If oFso.FolderExists(sFolder) Then
Set Folder = oFso.GetFolder(sFolder)
For Each Subfolder in Folder.Subfolders
sSubFolders = sSubFolders & Subfolder.Path & ","
Next 'Subfolder
End If
If f64 AND oFso.FolderExists(Wow64Folder(sFolder)) Then
Set Folder = oFso.GetFolder(Wow64Folder(sFolder))
For Each Subfolder in Folder.Subfolders
sSubFolders = sSubFolders & Subfolder.Path & ","
Next 'Subfolder
End If
If Len(sSubFolders)>0 Then arrSubFolders =
RemoveDuplicates(Split(Left(sSubFolders,Len(sSubFolders)-1),","))
EnumFolders = Len(sSubFolders)>0
End Function 'EnumFolders
'==================================================================================
=====================
If dicKeepFolder.Exists(LCase(sFolder)) Then
If NOT fForce Then
LogOnly " - Disallowing the delete of still required keypath element: "
& sFolder
Exit Sub
Else
LogOnly " - Enforced delete of still required keypath element: " &
sFolder
LogOnly " Remaining applications will need a repair!"
End If
End If
If f64 Then
If dicKeepFolder.Exists(LCase(Wow64Folder(sFolder))) Then
If NOT fForce Then
LogOnly " - Disallowing the delete of still required keypath element: "
& sFolder
Exit Sub
Else
LogOnly " - Enforced delete of still required keypath element: " &
sFolder
LogOnly " Remaining applications will need a repair!"
End If
End If
End If
CheckError "DeleteEmptyFolder"
On Error Goto 0
End Sub 'DeleteEmptyFolder
'==================================================================================
=====================
'Wrapper to delete a folder and remove the empty parent folder structure
Sub SmartDeleteFolder(sFolder)
If oFso.FolderExists(sFolder) Then
If Not fDetectOnly Then
LogOnly " Request SmartDelete for folder: " & sFolder
SmartDeleteFolderEx sFolder
Else
LogOnly " Simulate request SmartDelete for folder: " & sFolder
End If
End If
If f64 AND oFso.FolderExists(Wow64Folder(sFolder)) Then
If Not fDetectOnly Then
LogOnly "Request SmartDelete for folder: " & Wow64Folder(sFolder)
SmartDeleteFolderEx Wow64Folder(sFolder)
Else
LogOnly "Simulate request SmartDelete for folder: " &
Wow64Folder(sFolder)
End If
End If
End Sub 'SmartDeleteFolder
'==================================================================================
=====================
Dim Folder
Function HiveString(hDefKey)
On Error Resume Next
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
'==================================================================================
=====================
Function RegKeyExists(hDefKey,sSubKeyName)
Dim arrKeys
RegKeyExists = False
If oReg.EnumKey(hDefKey,sSubKeyName,arrKeys) = 0 Then RegKeyExists = True
End Function
'==================================================================================
=====================
Function RegValExists(hDefKey,sSubKeyName,sName)
Dim arrValueTypes, arrValueNames
Dim i
RegValExists = False
If Not RegKeyExists(hDefKey,sSubKeyName) Then Exit Function
If sName = "" Then
RegValExists = True
Exit Function
End If
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
'==================================================================================
=====================
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 "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(34))
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)
End If
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 "11","REG_QWORD"
RetVal = oReg.GetQWORDValue(hDefKey,sSubKeyName,sName,sValue)
If Not RetVal = 0 AND f64 Then RetVal =
oReg.GetQWORDValue(hDefKey,Wow64Key(hDefKey, sSubKeyName),sName,sValue)
Case Else
RetVal = -1
End Select 'sValue
RegReadValue = (RetVal = 0)
End Function 'RegReadValue
'==================================================================================
=====================
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
'==================================================================================
=====================
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
'==================================================================================
=====================
sRealName = sName
If UCase(sName) = "(DEFAULT)" Then sRealName = ""
If RegValExists(hDefKey,sSubKeyName,sRealName) Then
On Error Resume Next
If RegReadValue(hDefKey,sSubKeyName,sName,sValue,"REG_MULTI_SZ") Then
LogOnly " - Disallowing unsafe delete of REG_MULTI_SZ: " &
HiveString(hDefKey) & "\" & sSubKeyName & sName
Exit Sub
End If
If Not fDetectOnly Then
LogOnly " - Delete registry value: " & HiveString(hDefKey) & "\" &
sSubKeyName & " -> " & sName
iRetVal = 0
iRetVal = oReg.DeleteValue(hDefKey, sSubKeyName, sRealName)
CheckError "RegDeleteValue"
If NOT (iRetVal=0) Then LogOnly " Delete failed. Return value:
"&iRetVal
Else
LogOnly " - Simulate delete registry value: " & HiveString(hDefKey) &
"\" & sSubKeyName & " -> " & sName
End If
On Error Goto 0
End If 'RegValExists
If f64 Then
sWow64Key = Wow64Key(hDefKey, sSubKeyName)
If RegValExists(hDefKey,sWow64Key,sRealName) Then
On Error Resume Next
If RegReadValue(hDefKey,sSubKeyName,sName,sValue,"REG_MULTI_SZ") Then
LogOnly " - Disallowing unsafe delete of REG_MULTI_SZ: " &
HiveString(hDefKey) & "\" & sSubKeyName & sName
Exit Sub
End If
If Not fDetectOnly Then
LogOnly " - Delete registry value: " & HiveString(hDefKey) & "\" &
sWow64Key & " -> " & sName
iRetVal = 0
iRetVal = oReg.DeleteValue(hDefKey, sWow64Key, sRealName)
CheckError "RegDeleteValue"
If NOT (iRetVal=0) Then LogOnly " Delete failed. Return value:
"&iRetVal
Else
LogOnly " - Simulate delete registry value: " & HiveString(hDefKey)
& "\" & sWow64Key & " -> " & sName
End If
On Error Goto 0
End If 'RegKeyExists
End If
End Sub 'RegDeleteValue
'==================================================================================
=====================
If dicKeepReg.Exists(LCase(sSubKeyName)) Then
If NOT fForce Then
LogOnly " - Disallowing the delete of still required keypath element: "
& HiveString(hDefKey) & "\" & sSubKeyName
Exit Sub
Else
LogOnly " - Enforced delete of still required keypath element.
Remaining applications will need a repair!"
End If
End If
If f64 Then
If dicKeepReg.Exists(LCase(Wow64Key(hDefKey, sSubKeyName))) Then
If NOT fForce Then
LogOnly " - Disallowing the delete of still required keypath
element: " & HiveString(hDefKey) & "\" & sSubKeyName
Exit Sub
Else
LogOnly " - Enforced delete of still required keypath element.
Remaining applications will need a repair!"
End If
End If
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
iRet = 0
sQuery = "Select * From Win32_Service Where Name='" & sService & "'"
Set Services = oWmiLocal.Execquery(sQuery)
'Stop the service
For Each Service in Services
If UCase(Service.State) = "STARTED" Then iRet = Service.StopService
If UCase(Service.State) = "RUNNING" Then iRet = Service.StopService
Next 'Service
StopService = (iRet = 0)
End Function 'StopService
'==================================================================================
=====================
'Delete a service
Sub DeleteService(sService)
Dim Services, Service, Processes, Process
Dim sQuery, sStates
Dim iRet
sStates = "STARTED;RUNNING"
sQuery = "Select * From Win32_Service Where Name='" & sService & "'"
Set Services = oWmiLocal.Execquery(sQuery)
Function GetProductID(sProdID)
Dim sReturn
'-------------------------------------------------------------------------------
' LogH
'
' Write a header log string to the log file
'-------------------------------------------------------------------------------
Sub LogH (sLog)
LogStream.WriteLine ""
sLog = sLog & vbCrLf & String(Len(sLog), "=")
If NOT fQuiet AND fCScript Then wscript.echo ""
If NOT fQuiet AND fCScript Then wscript.echo sLog
LogStream.WriteLine sLog
End Sub 'Logh
'-------------------------------------------------------------------------------
' LogH1
'
' Write a header log string to the log file
'-------------------------------------------------------------------------------
Sub LogH1 (sLog)
LogStream.WriteLine ""
sLog = sLog & vbCrLf & String(Len(sLog), "-")
If NOT fQuiet AND fCScript Then wscript.echo ""
If NOT fQuiet AND fCScript Then wscript.echo sLog
LogStream.WriteLine sLog
End Sub 'LogH1
'-------------------------------------------------------------------------------
' LogH2
'
' Write w/o indent Cmd window and the log file
'-------------------------------------------------------------------------------
Sub LogH2 (sLog)
If NOT fQuiet AND fCScript Then wscript.echo sLog
LogStream.WriteLine ""
LogStream.WriteLine sLog
End Sub 'LogH2
'-------------------------------------------------------------------------------
' Log
'
' Echos the log string to the Cmd window and the log file
'-------------------------------------------------------------------------------
Sub Log (sLog)
If NOT fQuiet AND fCScript Then wscript.echo sLog
If sLog = "" Then
LogStream.WriteLine
Else
LogStream.WriteLine " " & Time & ": " & sLog
End If
End Sub 'Log
'-------------------------------------------------------------------------------
' LogOnly
'
' Commits the log string to the log file
'-------------------------------------------------------------------------------
Sub LogOnly (sLog)
If sLog = "" Then
LogStream.WriteLine
Else
LogStream.WriteLine " " & Time & ": " & sLog
End If
End Sub 'Log
'==================================================================================
=====================
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
'==================================================================================
=====================
iArgCnt = Wscript.Arguments.Count
If iArgCnt > 1 Then
If wscript.Arguments(1) = "UAC" Then
If wscript.arguments.count = 2 Then iArgCnt = 0
End If
End If
If iArgCnt = 0 Then
If sDefault = "" Then
'Create the log
CreateLog
Log "No argument specified. Preparing user prompt" & vbCrLf
FindInstalledOProducts
If dicInstalledSku.Count > 0 Then sDefault =
Join(RemoveDuplicates(dicInstalledSku.Items),",") Else sDefault = "CLIENTALL"
sDefault = InputBox("Enter a list of " & ONAME & " products to remove"
& vbCrLf & vbCrLf & _
"Examples:" & vbCrLf & _
"CLIENTALL" & vbTab & "-> all Client products" & vbCrLf & _
"SERVER" & vbTab & "-> all Server products" & vbCrLf & _
"ALL" & vbTab & vbTab & "-> all Server & Client products" &
vbCrLf & _
"ProPlus,PrjPro" & vbTab & "-> ProPlus and Project" & vbCrLf &_
"?" & vbTab & vbTab & "-> display Help", _
SCRIPTFILE & " - " & ONAME & " remover", _
sDefault)
Case "?"
ShowSyntax
Case "ALL"
fRemoveAll = True
fRemoveOse = False
Case "CLIENTSUITES"
fRemoveCSuites = True
fRemoveOse = False
Case "CLIENTSTANDALONE"
fRemoveCSingle = True
fRemoveOse = False
Case "CLIENTALL"
fRemoveCSuites = True
fRemoveCSingle = True
fRemoveOse = False
Case "SERVER"
fRemoveSrv = True
fRemoveOse = False
Case "ALL,OSE"
fRemoveAll = True
fRemoveOse = True
Case Else
fRemoveAll = False
fRemoveOse = False
sSkuRemoveList = sArg0
End Select
Case "?","/?","-?"
ShowSyntax
Case "/B","/BYPASS"
If UBound(arrArguments) > iCnt Then
If InStr(arrArguments(iCnt + 1), "1") > 0 Then fBypass_Stage1 =
True
If InStr(arrArguments(iCnt + 1), "2") > 0 Then fBypass_Stage2 =
True
If InStr(arrArguments(iCnt + 1), "3") > 0 Then fBypass_Stage3 =
True
If InStr(arrArguments(iCnt + 1), "4") > 0 Then fBypass_Stage4 =
True
End If
Case "/FR","/FASTREMOVE"
fBypass_Stage1 = True
fSkipSD = True
Case "/F","/FORCE"
fForce = True
Case "/K","/KEEPUSERSETTINGS"
fKeepUser = True
Case "/KEEPLYNC"
fRemoveLync = False
Case "/REMOVELYNC"
fRemoveLync = True
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 "/NOCANCEL"
fNoCancel = True
Case "/NOREBOOT"
fNoReboot = True
Case "/NE","/NOELEVATE"
fNoElevate = True
Case "/O","/OSE"
fRemoveOse = True
Case "/P","/PREVIEW","/DETECTONLY"
fDetectOnly = True
Case "/Q","/QUIET"
fQuiet = True
Case "/QB"
fQuiet = True
fBasic = True
Case "/QND"
fBypass_Stage1 = True
fBypass_Stage2 = True
fBypass_Stage3 = True
fRemoveOse = True
fRemoveOspp = True
fRemoveAll = True
fSkipSD = True
fForce = True
Case Else
End Select
Next 'iCnt
If Not fLogInitialized Then CreateLog
LogH2 "Arguments: " & sArguments & vbCrLf
'-------------------------------------------------------------------------------
' CreateLog
'
' Create the removal log file
'-------------------------------------------------------------------------------
Sub CreateLog
Dim DateTime
Dim sLogName
LogH2 "Microsoft Customer Support Services - " & ONAME & " Removal Utility" &
vbCrLf & vbCrLf & _
"Version: " & vbTab & SCRIPTVERSION & vbCrLf & _
"64 bit OS: " & vbTab & f64 & vbCrLf & _
"Removal start: " & vbTab & Time & vbCrLf & _
"OS Details: " & sOSinfo & vbCrLf
fLogInitialized = True
End Sub 'CreateLog
'-------------------------------------------------------------------------------
' RelaunchAs64Host
'
' Relaunch self with 64 bit CScript host
'-------------------------------------------------------------------------------
Sub RelaunchAs64Host
Dim Argument, sCmd
Dim fQuietRelaunch
fQuietRelaunch = False
sCmd = Replace(LCase(wscript.Path), "syswow64", "sysnative") & "\cscript.exe "
& Chr(34) & WScript.scriptFullName & Chr(34)
If fQuiet Then fQuietRelaunch = True
If Wscript.Arguments.Count > 0 Then
For Each Argument in Wscript.Arguments
sCmd = sCmd & " " & chr(34) & Argument & chr(34)
Select Case UCase(Argument)
Case "/Q", "/QUIET"
fQuietRelaunch = True
End Select
Next 'Argument
End If
sCmd = sCmd & " /ChangedHostBitness"
If fQuietRelaunch Then
sCmd = Replace (sCmd, "\cscript.exe", "\wscript.exe")
Wscript.Quit CLng(oWShell.Run (sCmd, 0, True))
Else
Wscript.Quit CLng(oWShell.Run (sCmd, 1, True))
End If
'-------------------------------------------------------------------------------
' RelaunchAsCScript
'
' Relaunch self with Cscript as host
'-------------------------------------------------------------------------------
Sub RelaunchAsCScript
Dim Argument
Dim sCmdLine
sCmdLine = "cmd.exe /c " & 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
Log "Relaunching with CScript as host. Full command: " & sCmdLine
Wscript.Quit CLng(oWShell.Run(sCmdLine, 1, True))
'-------------------------------------------------------------------------------
' 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
'-------------------------------------------------------------------------------
' 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
'-------------------------------------------------------------------------------
' 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
'-------------------------------------------------------------------------------
' 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
'-------------------------------------------------------------------------------
' ShowSyntax
'
' Show the expected syntax for the script usage
'-------------------------------------------------------------------------------
Sub ShowSyntax
TmpKeyCleanUp
Wscript.Echo vbCrLf & _
SCRIPTFILE & " V " & SCRIPTVERSION & vbCrLf & _
"Copyright (c) Microsoft Corporation. All Rights Reserved" & vbCrLf &
vbCrLf & _
"Microsoft Customer Support Services - " & ONAME & " Removal Utility"
& vbCrLf & vbCrLf & _
SCRIPTFILE & " helps to remove " & ONAME & " Server & Client products"
& vbCrLf & vbCrLf & _
"Usage:" & vbTab & SCRIPTFILE & " [List of config ProductIDs]
[Options]" & vbCrLf & vbCrLf & _
vbTab & "/? ' Displays this help"& vbCrLf &_
vbTab & "/Log [LogfolderPath] ' Custom folder for log files" &
vbCrLf & _
vbTab & "/SkipSD ' Skips the ShortcutDetection in
local profiles" & vbCrLf & _
vbTab & "/NoCancel ' Setup.exe and Msiexec.exe have
no Cancel button" & vbCrLf &_
vbTab & "/Quiet ' Script, Setup.exe and
Msiexec.exe run quiet with no UI" & vbCrLf &_
vbTab & "/Preview ' Run this script to preview what
would get removed"& vbCrLf & vbCrLf & _
"Examples:"& vbCrLf & _
vbTab & SCRIPTFILE & " CLIENTSUITES ' Remove all " & ONAME & "
Client suites/products" & vbCrLf &_
vbTab & SCRIPTFILE & " CLIENTALL ' Remove all " & ONAME & "
Client products" & vbCrLf &_
vbTab & SCRIPTFILE & " SERVER ' Remove all " & ONAME & "
Server products" & vbCrLf &_
vbTab & SCRIPTFILE & " ALL ' Remove all " & ONAME & "
Server & Client products" & vbCrLf &_
vbTab & SCRIPTFILE & " ProPlus,PrjPro ' Remove ProPlus and Project" &
vbCrLf
Wscript.Quit
End Sub 'ShowSyntax
'==================================================================================
=====================