'==========================================================================
'
' NAME: Install-UniversalForwarder-6.6.4.0-M-R1.vbs
'
' AUTHOR:  Max Erenburg 
' DATE  : 4/30/2018
'
' COMMENT: This script will verify that Splunk UniversalForwarder is installed properly
' on servers and DC's (at this time until EASE integration, if ever).
' *** X64 bit package only *** 
' Update 05/24/2018 = Server Core installations dont have hidden service installs, added code.
'==========================================================================

Option Explicit

Dim vDate, vTime, altTime, altDate, vDateTime
vDateTime = Now

Dim oShell, oFSO, oProcessEnv, sScript, PUBLICPROPERTY, sSVCName, iErrCode, sMsg
Dim sDebugBlat, sMSIDebugQA, sSuccess, sPilot
Dim sMailbox1, sMailbox2, sRelayHost, sCN, sFQDN, sTry
Dim sSrcRoot, sSystem32, sLogDir, sScriptsDir, sEmailDir, sDebugLog
Dim sDomFQDN, sLib, sBlat, sEngKey
Dim sCoreBlat, sCoreBlat2, sCoreWMI, sCoreInfo, sCoreInfo2, sCoreInfo3, DebugLog
Dim oWMI, sWMIFailed, sWMIMsgBody2
Dim ProductName, IsServer, IsServerCore, CSDver, s64Bit, DC
Dim dtmSystemUptime, iMSIVal, oMSIinstaller, AppName, MSIver, GUID, sAlreadyInst, sFound

Set oShell = CreateObject("WScript.Shell")
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oProcessEnv = oShell.Environment("PROCESS")

' Packager's defined variable's for MSI based installations
Const PRODUCTCODE = "{7B6B56FA-0ACA-406A-8F05-7C54B589563B}" ' x64 package
Const DEPLOYNAME = "UniversalForwarder-x64-6.6.4.0"
Const SIDE = "-M"
Const RELEASE = "-R1"
Const VERSION = "6.6.4.0"
sScript = "Install-" & DEPLOYNAME & SIDE & RELEASE
PUBLICPROPERTY = "AGREETOLICENSE=Yes DEPLOYMENT_SERVER=192.168.15.2:8089"
sSVCName = "SplunkForwarder"

sDebugBlat = "False" ' Email if blat found missing and copied down local.
sMSIDebugQA = "False" ' QA Mode for MSI '(used to speed up large package testing by running "Notepad" instead of actual MSI/EXE to test pre/post functions
sSuccess = "False" ' Set to False if you dont want success emails. ' For enterprise deployment set to false, for one of installations leave as True
sPilot = "False" ' Set to False if you dont want attachment of debug file to success emails. ' Use for QA/UAT, once ready for Production deployments set to False

sMailbox1 = "merenburg@theorchard.com" : sMailbox2 = ""
sRelayHost = "smtp-relay.gmail.com"
sCN = oProcessEnv("COMPUTERNAME")
sFQDN = "@TheOrchard.com"
sTry = "2"

sSrcRoot = Replace(WScript.ScriptFullName, WScript.ScriptName, "")
sSystem32 = oProcessEnv("SYSTEMROOT") & "\system32\"
sLogDir = oProcessEnv("SYSTEMROOT") & "\EngLogs"
sScriptsDir = sLogDir & "\Scripts"
sEmailDir = sLogDir & "\Email"
sDebugLog = sScriptsDir & "\" & sScript & ".log"

sBlat = sSystem32 & "blat.exe"
sEngKey = "HKLM\SOFTWARE\ORCDENG\"

' Initialize WMI connection to cimv2
On Error Resume Next 
Set oWMI = GetObject("winmgmts:\\.\root\cimv2")
If Err.Number <> 0 Then
	iErrCode = Err.Number
	sWMIFailed = "Failed"
	sWMIMsgBody2 = Now & "__ Script was unable to successfully connect to cimv2, Error code: " & iErrCode & ", installations are dependent on WMI being healthy, cannot proceed."
End If
On Error GoTo 0

sMsg = "Scriptname: " & WScript.ScriptName
sMsg = sMsg & "|ScriptPath: " & WScript.ScriptFullName

' Get Domain Name we are working with so we dont have to have additional copies of same script per AD Forest/Domain.
Call GetDomainName
sLib = "\\" & sDomFQDN & "\netlogon\lib\"

' Ensure email alerts are available
Call CopyBlat

' Create directory(s) for local centralized logging
Call CreateLogDirs

' Create debug log or append to log if this script has been run before
Call CreateDebugLog("FirstCheck")

' Get what OS, CSD version are we working with
Call GetOSInfo
If s64Bit = "0" Then WSHLog "CriticalFailure", "This script does not support 32 bit OS."

If sWMIFailed = "Failed" Then 'fail with hard error as we need WMI up and running (health to perform installs, etc..)
	If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
	WSHLog "CriticalFailure", sWMIMsgBody2
End If

' Check if DC Function
Call IsDC

' Check if product is already Installed
Call ChkPkgAlreadyInstalled

If sAlreadyInst = "No" Then
	If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
	DebugLog.WriteLine(Now & "__ Product: " & PRODUCTCODE & " was not found installed.")

	' Install MSI package
	Call MSIPkgInstall("/qb!")
	Call MoveInsLog
	Call Tattoo("new")

ElseIf sAlreadyInst = "Upgrade" Then
	If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
	DebugLog.WriteLine(Now & "__ Proceeding to upgrade to newer version.")
	' Uninstall old package
	Call MSIUninstall("/qb!")
	' Install package
	Call MSIPkgInstall("/qb!")
	Call MoveInsLog
	Call Tattoo("Upgrade")

ElseIf sAlreadyInst = "Reinstall" Then
	If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
	DebugLog.WriteLine(Now & "__ Proceeding to reinstall.")
	' Install package
	Call MSIPkgInstall("/qb!")
	Call MoveInsLog
	Call Tattoo("Reinstall")

ElseIf sAlreadyInst = "Yes" Then' Going to run a health check on installation
	Call AppHealthCheck
	If sAlreadyInst = "Reinstall" Then
		If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
		DebugLog.WriteLine(Now & "__ Proceeding to reinstall.")
		' Uninstall old package
		Call MSIUninstall("/qb!")
		' Install package
		Call MSIPkgInstall("/qb!")
		Call MoveInsLog
		Call Tattoo("Reinstall")
	Else
		Call MoveInsLog
		If IsObject(DebugLog) Then DebugLog.WriteLine(Now & "__ AppHealthCheck function passed, nothing to do.")
	End If
Else
	If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
	DebugLog.WriteLine(Now & "__ Found no value for sAlreadyInst, must be some condition not accounted for. Use this asset for reference to the condition.")
	iErrCode = "999"
End If

If IsObject(DebugLog) Then DebugLog.WriteLine(Now & "__ Wrapper execution complete, total execution time: " & DateDiffToWords(vDateTime,Now))
WSHLog "Information", "Wrapper execution complete, total execution time: " & DateDiffToWords(vDateTime,Now)

' Log/email exit code, cleanup and exit
If Not(IsNull(iMSIVal) Or IsEmpty(iMSIVal)) Then
	If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
	DebugLog.WriteLine(Now & "__ Exiting... Wrapper exit code: " & iMSIVal)
	If (sSuccess = "True") And (sPilot = "False") And (sCoreBlat = "") Then Email sScript & "  Status", "Wrapper exit code: " & iMSIVal & "|" & sMsg
	Call Cleanup(sScript & "  Status", "Wrapper exit code: " & iMSIVal & "|" & sMsg)
	WScript.Quit(iMSIVal)
ElseIf Not (IsNull(iErrCode) Or IsEmpty(iErrCode)) Then
	If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
	DebugLog.WriteLine(Now & "__ Exiting... Wrapper exit code : " & iErrCode)
	If (sSuccess = "True") And (sPilot = "False") And (sCoreBlat = "") Then Email sScript & "  Status", "Wrapper exit code : " & iErrCode & "|" & sMsg
	Call Cleanup(sScript & "  Status", "Wrapper exit code : " & iErrCode & "|" & sMsg)
	WScript.Quit(iErrCode)
Else
	If IsObject(DebugLog) Then DebugLog.WriteLine(Now & "__ Exiting... Wrapper exit code  : " & Err.Number)
	If (sSuccess = "True") And (sPilot = "False") And (sCoreBlat = "") Then Email sScript & "  Status", "Wrapper exit code  : " & Err.Number & "|" & sMsg
	Call Cleanup(sScript & "  Status", "Wrapper exit code  : " & Err.Number & "|" & sMsg)
	WScript.Quit
End If

' ------   Packager's defined Functions/Subs section    -------

' Application/Installation Health Check Function
Function AppHealthCheck
	On Error Resume Next
	'check if service exists and base on up time of asset if process is running or not
	Dim sPFN, sPD, ChkSVC, ChkProc
	sPFN = "Splunk UF"
	sPD = oProcessEnv("ProgramFiles") & "\SplunkUniversalForwarder\"
	ChkSVC = CheckService(sSVCName, "NULL", "NULL", "NoCheck", "NULL", "Required")
	If ChkSVC = "DoesntExist" Then
		If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
		DebugLog.WriteLine(Now & "__ While performing an installation health check, we found that the " & sPFN & " msi installation is registered, but the service " & sSVCName & " was found to be missing.")
		sAlreadyInst = "Reinstall"
		Call CheckforRemnants
	Else
		ChkProc = CheckProcess("Exact", "splunkd.exe", Null, "Check", Null)
		If ChkProc = "notrunning" Then
			Call GetUpTime("n") ' in minutes
			If dtmSystemUptime < 1 Then
'''''					'Msgbox "Just booted up"
				If IsObject(DebugLog) Then DebugLog.WriteLine(Now & "__ " & sSVCName & " process was not found running but since the uptime is only " & dtmSystemUptime & " mins. we expect it to be running within an uptime of 1 min., so we know it hasn't had a chance to start possibly. Will perform a quick file sanity check.")
				WSHLog "Information", sSVCName & " process was not found running but since the uptime is only " & dtmSystemUptime & " mins. we expect it to be running within an uptime of 1 min., so we know it hasn't had a chance to start possibly. Will perform a quick file sanity check."
				Call SanityCheck
'''''
			Else
				If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
				DebugLog.WriteLine(Now & "__ Found system uptime to be " & dtmSystemUptime & ", but service was found not running. will attempt to start it.")
				ChkSVC = CheckService(sSVCName, "Auto", "Automatic", "Running", "NULL", "Required")
				If ChkSVC = "FailedtostartService" Then
					Dim sExePath, ExePathKEY
					sExePath = "HKLM\System\CurrentControlSet\Services\" & sSVCName & "\ImagePath"
					ExePathKEY = GetRegData(sExePath, "{default}")
					If ExePathKEY = "{default}" Then
						DebugLog.WriteLine(Now & "__ Reg key " & sExePath & " does not exist. Sending email to consider performing a reinstall to this condition in the future.")
						'sAlreadyInst = "Reinstall"
						WSHLog "CriticalFailure", "Found " & sPFN & " registered as installed, service was found to exist but not running, failed to start. System uptime is " & dtmSystemUptime & ". Executable path not found in registry." 
					Else
						DebugLog.WriteLine(Now & "__ Found service registry key with path to executable to be " & ExePathKEY & ". Going to check file existence and version, etc.")
						If Not InStr(1, ExePathKEY, Chr(34), 1) = 0 Then
							Dim oSplit, oExePath : oSplit = Split(ExePathKEY, Chr(34), 2, 1)
							oExePath = Split(oSplit, (1), Chr(34), 2, 1)
							ExePathKEY = oExePath(0)
						End If
						If Not oFSO.FileExists(ExePathKEY) Then
							DebugLog.WriteLine(Now & "__ File in service image path: " & ExePathKEY & " does not exist on file system. Sending email to consider performing a reinstall to this condition in the future.")
							'sAlreadyInst = "Reinstall"
							WSHLog "CriticalFailure", "Found " & sPFN & " registered as installed, service was found to exist but not running, failed to start. System uptime is " & dtmSystemUptime & ". File in service image path: " & ExePathKEY & " does not exist on file system." 
						Else
							DebugLog.WriteLine(Now & "__ Found file in service image path: " & ExePathKEY & " exists on file system. Going to check file counts in " & sPFN & " bin directory.")
							Dim sCheckPath1, f, fc
							sCheckPath1 = sPD & "bin"
							If Not oFSO.FolderExists(sCheckPath1) Then
								DebugLog.WriteLine(Now & "__ Path " & sCheckPath1 & " not found to exist on file system. Sending email to consider performing a reinstall to this condition in the future.")
								'sAlreadyInst = "Reinstall"
								WSHLog "CriticalFailure", "Found " & sPFN & " registered as installed, service was found to exist but not running, failed to start. System uptime is " & dtmSystemUptime & ". Path " & sCheckPath1 & " not found to exist on file system." 
							Else
								Set f = oFSO.GetFolder(sCheckPath1)
								Set fc = f.Files
								If fc.Count < 87 Then
									DebugLog.WriteLine(Now & "__ Found " & fc.Count & " files exist in " & sCheckPath1 & ". Should contain 87 files. Sending email to consider performing a reinstall to this condition in the future.")
									'sAlreadyInst = "Reinstall"
									WSHLog "CriticalFailure", "Found " & sPFN & " registered as installed, service was found to exist but not running, failed to start. System uptime is " & dtmSystemUptime & ". Found " & fc.Count & " files exist in " & sCheckPath1 & ". Should contain 87 files." 
								Else
									DebugLog.WriteLine(Now & "__ Found " & sCheckPath1 & " directory exists with " & fc.Count & " files in it.")
									'sAlreadyInst = "Reinstall"
									WSHLog "CriticalFailure", "Found " & sPFN & " registered as installed, service was found to exist but not running, failed to start. System uptime is " & dtmSystemUptime & ". Found " & sCheckPath1 & " directory exists with " & fc.Count & " files in it. We are not quite sure why the service is not starting." 								
								End If
							End If
						End If
					End If
				End If
			End If			
		End If
		Call SanityCheck
	End If
	On Error GoTo 0
End Function

' Various sanity checks for health of installation
Function SanityCheck
	On Error Resume Next
	Dim sPFN, sPD
	sPFN = "Splunk UF"
	sPD = oProcessEnv("ProgramFiles") & "\SplunkUniversalForwarder\"
	If Not IsServerCore = "True" Then
		'Check other 3 hidden services existance (sanity check) / not installed on Server Core
		Dim sImagePath1, ImagePath1KEY, sImagePath2, ImagePath2KEY, sImagePath3, ImagePath3KEY, sCritical,	sCriticalFile
		sImagePath1 = "HKLM\SYSTEM\CurrentControlSet\Services\splknetdrv\ImagePath"
		ImagePath1KEY = GetRegData(sImagePath1, "{default}")
		If ImagePath1KEY = "{default}" Then
			If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
			DebugLog.WriteLine(Now & "__ Reg key " & sImagePath1 & " does not exist.") '  Going to reinstall.
			'sAlreadyInst = "Reinstall" ' future force resinstall if we see these conditions exist.
			sCritical = "Yes"
		ElseIf InStr(1, UCase(ImagePath1KEY), UCase("system32\DRIVERS\splknetdrv.sys"), 1) = 0 Then
			If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
			DebugLog.WriteLine(Now & "__ Found " & sImagePath1 & " reg key with a value of " & ImagePath1KEY & ", which is not what we expected?")
			'sAlreadyInst = "Reinstall" ' future force resinstall if we see these conditions exist.
			sCritical = "Yes"
		End If
		sImagePath2 = "HKLM\SYSTEM\CurrentControlSet\Services\splunkdrv\ImagePath"
		ImagePath2KEY = GetRegData(sImagePath2, "{default}")
		If ImagePath2KEY = "{default}" Then
			If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
			DebugLog.WriteLine(Now & "__ Reg key " & sImagePath2 & " does not exist.") '  Going to reinstall.
			'sAlreadyInst = "Reinstall" ' future force resinstall if we see these conditions exist.
			sCritical = "Yes"
		ElseIf InStr(1, UCase(ImagePath2KEY), UCase("system32\DRIVERS\splunkdrv.sys"), 1) = 0 Then
			If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
			DebugLog.WriteLine(Now & "__ Found " & sImagePath2 & " reg key with a value of " & ImagePath2KEY & ", which is not what we expected?")
			'sAlreadyInst = "Reinstall" ' future force resinstall if we see these conditions exist.
			sCritical = "Yes"
		End If
		sImagePath3 = "HKLM\SYSTEM\CurrentControlSet\Services\SplunkMonitorNoHandle\ImagePath"
		ImagePath3KEY = GetRegData(sImagePath3, "{default}")
		If ImagePath3KEY = "{default}" Then
			If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
			DebugLog.WriteLine(Now & "__ Reg key " & sImagePath3 & " does not exist.") '  Going to reinstall.
			'sAlreadyInst = "Reinstall" ' future force resinstall if we see these conditions exist.
			sCritical = "Yes"
		ElseIf Not UCase(ImagePath3KEY) = UCase("system32\DRIVERS\SplunkMonitorNoHandleDrv.sys") Then
			If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
			DebugLog.WriteLine(Now & "__ Found " & sImagePath3 & " reg key with a value of " & ImagePath3KEY & ", which is not what we expected?")
			'sAlreadyInst = "Reinstall" ' future force resinstall if we see these conditions exist.
			sCritical = "Yes"
		End If
	End If
	If sCritical = "Yes" Then
		DebugLog.WriteLine(Now & "__ Found issue with one or more " & sPFN & " with hidden services.")
	End If

	Const ForReading = 1 : Const ForWriting = 2 : Const ForAppending = 8
	Dim DCFile, IFile, SFile, iErrDesc, ReadAll
	If Not oFSO.FileExists(sPD & "etc\passwd") Then ' See if hashed pwd file exists
		If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
		DebugLog.WriteLine(Now & "__ File " & sPD & "etc\passwd not found to exist on file system. Sending email to consider performing a reinstall to this condition in the future.")
		'sAlreadyInst = "Reinstall" ' future force resinstall if we see these conditions exist.
		sCriticalFile = "Yes"
	End If
	If Not oFSO.FileExists(sPD & "etc\system\local\deploymentclient.conf") Then
		If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
		DebugLog.WriteLine(Now & "__ File " & sPD & "etc\system\local\deploymentclient.conf not found to exist on file system. Sending email to consider performing a reinstall to this condition in the future.")
		'sAlreadyInst = "Reinstall" ' future force resinstall if we see these conditions exist.
		sCriticalFile = "Yes"
	Else
   		Set DCFile = oFSO.OpenTextFile(sPD & "etc\system\local\deploymentclient.conf", ForReading, True)
		If Err.Number <> 0 Then
			iErrCode = Err.Number
			iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
			Call GetWhoIsRunningScript
			WSHLog "CriticalFailure", "Attempt to read file " & sPD & "etc\system\local\deploymentclient.conf, failed. Error code: " & iErrDesc
		Else
			ReadAll = DCFile.ReadAll
			If InStr(1, UCase(ReadAll), UCase("targetUri = 192.168.15.2:8089"), 1) = 0 Then ' 0 is not found 
				If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
				DebugLog.WriteLine(Now & "__ Found file " & sPD & "etc\system\local\deploymentclient.conf contained no or other reference then to GSIRT SIEM 192.168.15.2:8089")
				sCriticalFile = "Yes"
			End If
		End If
	End If
	If Not oFSO.FileExists(sPD & "etc\system\local\inputs.conf") Then
		If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
		DebugLog.WriteLine(Now & "__ File " & sPD & "etc\system\local\inputs.conf not found to exist on file system. Sending email to consider performing a reinstall to this condition in the future.")
		'sAlreadyInst = "Reinstall" ' future force resinstall if we see these conditions exist.
		sCriticalFile = "Yes"
	Else
   		Set IFile = oFSO.OpenTextFile(sPD & "etc\system\local\inputs.conf", ForReading, True)
		If Err.Number <> 0 Then
			iErrCode = Err.Number
			iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
			Call GetWhoIsRunningScript
			WSHLog "CriticalFailure", "Attempt to read file " & sPD & "etc\system\local\inputs.conf, failed. Error code: " & iErrDesc
		Else
			ReadAll = IFile.ReadAll
			If InStr(1, UCase(ReadAll), UCase("host = " & sCN), 1) = 0  Then  ' 0 is not found 
				If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
				DebugLog.WriteLine(Now & "__ Found file " & sPD & "etc\system\local\inputs.conf contained no or other reference then to host = " & sCN)
				sCriticalFile = "Yes"
			End If
		End If
	End If
	If Not oFSO.FileExists(sPD & "etc\system\local\server.conf") Then
		If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
		DebugLog.WriteLine(Now & "__ File " & sPD & "etc\system\local\server.conf not found to exist on file system. Sending email to consider performing a reinstall to this condition in the future.")
		'sAlreadyInst = "Reinstall" ' future force resinstall if we see these conditions exist.
		sCriticalFile = "Yes"
	Else
   		Set SFile = oFSO.OpenTextFile(sPD & "etc\system\local\server.conf", ForReading, True)
		If Err.Number <> 0 Then
			iErrCode = Err.Number
			iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
			Call GetWhoIsRunningScript
			WSHLog "CriticalFailure", "Attempt to read file " & sPD & "etc\system\local\server.conf, failed. Error code: " & iErrDesc
		Else
			ReadAll = SFile.ReadAll
			If InStr(1, UCase(ReadAll), UCase("serverName = " & sCN), 1) = 0  Then  ' 0 is not found 
				If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
				DebugLog.WriteLine(Now & "__ Found file " & sPD & "etc\system\local\server.conf contained no or other reference then to serverName = " & sCN)
				sCriticalFile = "Yes"
			End If
		End If
	End If
	If sCriticalFile = "Yes" Then
		DebugLog.WriteLine(Now & "__ Found issue with " & sPFN & " configuration file(s).")
	End If
	
	If (sCritical = "Yes" AND sCriticalFile = "Yes") Then
		WSHLog "CriticalFailure", "Found issue with both " & sPFN & " hidden service(s) and configuration file(s), see attached log." 
	ElseIf sCritical = "Yes" Then
		WSHLog "CriticalFailure", "Found issue with " & sPFN & " hidden service(s), see attached log." 
	ElseIf sCriticalFile = "Yes" Then
		WSHLog "CriticalFailure", "Found issue with " & sPFN & " configuration file(s), see attached log." 
	End If
	On Error GoTo 0
End Function

' MSI package Installation Function
Function MSIPkgInstall(sDisplayOptions)
	Dim sMSIFile, sMSTFile, MSICMDLINE, sMsiLog, iInstVal
	sMSIFile = sSrcRoot & DEPLOYNAME & SIDE & RELEASE & ".msi"
	If NOT oFSO.FileExists(sMSIFile) Then
		iErrCode = "53"
		DebugLog.WriteLine(Now & "__ MSI specified to be installed in wrapper does not exist in source: " & sMSIFile)
		WSHLog "CriticalFailure", "MSI specified to be installed in wrapper does not exist in source: " & sMSIFile
	End If
	
	If oFSO.FileExists(sSrcRoot & DEPLOYNAME & SIDE & RELEASE & ".mst") Then
		sMSTFile = sSrcRoot & DEPLOYNAME & SIDE & RELEASE & ".mst"
	Else
		sMSTFile = Null
	End If
	sPilot = "True"
	Call Stamp
	If Not IsNull(sMSTFile) Then
		sMsiLog = Chr(34) & sScriptsDir & "\" & sScript & "-MSI_MST-" & altDate & "-" & altTime & ".log" & Chr(34)
		If PUBLICPROPERTY <> "" Then
			MSICMDLINE = "msiexec.exe REBOOT=ReallySuppress " & PUBLICPROPERTY & " TRANSFORMS=" & Chr(34) & sMSTFile & Chr(34) & " /i " & chr(34) & sMSIFile & chr(34) & " " & sDisplayOptions & " /L*v " & sMsiLog
		Else
			MSICMDLINE = "msiexec.exe REBOOT=ReallySuppress TRANSFORMS=" & Chr(34) & sMSTFile & Chr(34) & " /i " & chr(34) & sMSIFile & chr(34) & " " & sDisplayOptions & " /L*v " & sMsiLog
		End If
	Else
		sMsiLog = Chr(34) & sScriptsDir & "\" & sScript & "-MSI-" & altDate & "-" & altTime & ".log" & Chr(34)
		If PUBLICPROPERTY <> "" Then
			MSICMDLINE = "msiexec.exe REBOOT=ReallySuppress " & PUBLICPROPERTY & " /i " & chr(34) & sMSIFile & chr(34) & " " & sDisplayOptions & " /L*v " & sMsiLog
		Else
			MSICMDLINE = "msiexec.exe REBOOT=ReallySuppress /i " & chr(34) & sMSIFile & chr(34) & " " & sDisplayOptions & " /L*v " & sMsiLog
		End If
	End If

	DebugLog.WriteLine(Now & "__ Issuing installation commandline: " & MSICMDLINE)
	If sMSIDebugQA = "False" Then
		oProcessEnv("SEE_MASK_NOZONECHECKS") = 1
		iInstVal = oShell.Run(MSICMDLINE, 1, True)
		iMSIVal = iInstVal
		If iMSIVal = 0 Or iMSIVal = 3010 Then
			DebugLog.WriteLine(Now & "__ MSI installation completed, result code: " & iMSIVal)
		Else
			DebugLog.WriteLine(Now & "__ MSI installation FAILED, result code: " & iMSIVal)
			oProcessEnv.Remove("SEE_MASK_NOZONECHECKS")
			WSHLog "CriticalFailure", "MSI installation FAILED, result code: " & iMSIVal
		End If
	ElseIf sMSIDebugQA = "True" Then
		Dim sDebugTest
		sDebugTest = "NOTEPAD.EXE"
		iInstVal = oShell.Run(sDebugTest, 1, True)
	End If
End Function

' Move additonal log(s) from installation no msiexec based.
Function MoveInsLog
	On Error Resume Next
	If oFSO.FileExists(oProcessEnv("TEMP") & "\splunk.log") Then
		Call Stamp
		oFSO.MoveFile oProcessEnv("TEMP") & "\splunk.log", sScriptsDir & "\splunk_" & altDate & "-" & altTime & ".log"
	ElseIf oFSO.FileExists(oProcessEnv("SystemDrive") & "\Users\t0-tmoin\AppData\Local\Temp\splunk.log") Then
		Call Stamp
		oFSO.MoveFile oProcessEnv("SystemDrive") & "\Users\t0-tmoin\AppData\Local\Temp\splunk.log", sScriptsDir & "\splunk_tmoin_manual.log"
	End If
	On Error Goto 0
End Function

' Keep track of Install/reinstall/upgrades
Function Tattoo(sPriorState)
	On Error Resume Next
	Dim sSetDate, sSetTime, sQSD, sQST, sQIC, QICKey, iErrDesc, sCount
	Call Stamp : sSetDate = vDate : sSetTime = vTime		
	sQSD = sEngKey & "Scripts\S-UF\LastInstDate"
	sQST = sEngKey & "Scripts\S-UF\LastInstTime"
	oShell.RegWrite sQSD, sSetDate, "REG_SZ"
	If Err.Number = 0 Then
		DebugLog.WriteLine(Now & "__ Created reg key " & sQSD & " with value of " & sSetDate)
	Else
		iErrCode = Err.Number
		iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
		Call RegAlert(sQSD, sSetDate, iErrDesc)
	End If
	oShell.RegWrite sQST, sSetTime, "REG_SZ"
	If Err.Number = 0 Then
		DebugLog.WriteLine(Now & "__ Created reg key " & sQST & " with value of " & sSetTime)
	Else
		iErrCode = Err.Number
		iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
		Call RegAlert(sQST, sSetTime, iErrDesc)
	End If
	sQIC = sEngKey & "Scripts\S-UF\InstCount"
	QICKey = GetRegData(sQIC, "{default}")
	If QICKey = "{default}" Then
		If sPriorState = "Reinstall" Then
			sCount = "2"
		Else
			sCount = "1"
		End If
	Else
		sCount = QICKey + 1
	End If
	oShell.RegWrite sQIC, sCount, "REG_SZ"
	If Err.Number = 0 Then
		DebugLog.WriteLine(Now & "__ Created reg key " & sQIC & " with value of " & sCount)
	Else
		iErrCode = Err.Number
		iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
		Call RegAlert(sQIC, sCount, iErrDesc)
	End If
	If sPriorState = "Upgrade" Then
		Dim sQUC, QUCKey
		sQUC = sEngKey & "Scripts\S-UF\UpGradeCount"
		QUCKey = GetRegData(sQUC, "{default}")
		If QUCKey = "{default}" Then
			sCount = "1"
		Else
			sCount = QUCKey + 1
		End If
		oShell.RegWrite sQUC, sCount, "REG_SZ"
		If Err.Number = 0 Then
			DebugLog.WriteLine(Now & "__ Created reg key " & sQUC & " with value of " & sCount)
		Else
			iErrCode = Err.Number
			iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
			Call RegAlert(sQUC, sCount, iErrDesc)
		End If
	End If
	On Error GoTo 0
End Function

' Log failed registry key/value creation function
Sub RegAlert(sRegPath, sValue, iErrDesc)
	DebugLog.WriteLine(Now & "__ Failed to create reg key " & sRegPath & " with value of " & sValue & ", Error code: " & iErrDesc)
	WSHLog "CriticalFailure", "Failed to create reg key " & sRegPath & " with value of " & sValue & ", Error code: " & iErrDesc
End Sub

' Function Get system uptime
Function GetUpTime(interval)
	On Error Resume Next
	Dim OpSysSet, OpSys, dtmBootup, dtmLastBootupTime, iErrDesc
	Set OpSysSet = oWMI.ExecQuery("SELECT LastBootUpTime FROM Win32_OperatingSystem WHERE Primary = True")
	If Err.Number = 0 Then
		For Each OpSys in OpSysSet
			dtmBootup = OpSys.LastBootUpTime 
			dtmLastBootupTime = WMIDateStringToDate(dtmBootup) 
			dtmSystemUptime = DateDiff(interval, dtmLastBootupTime, Now)
		Next 
	Else
		iErrCode = Err.Number
		iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
		If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
		DebugLog.WriteLine(Now & "__ Critical issue, could not connect to WMI, cimv2:Win32_OperatingSystem to obtain system uptime. Error Code: "  & iErrDesc)
		WSHLog "Failure", "Failed to connect to WMI, cimv2:Win32_OperatingSystem to obtain system uptime. Error Code: "  & iErrDesc
		dtmSystemUptime = "Failed"
	End If
	sMsg = sMsg & "|System uptime: " & dtmSystemUptime & " minutes." ' Do not remove this last & "." otherwise it wraps
	Set OpSysSet = Nothing
	On Error GoTo 0	
End Function

' Function to convert UNC time to readable format 
Function WMIDateStringToDate(dtmBootup) 
	WMIDateStringToDate = CDate(Mid(dtmBootup, 5, 2) & "/" & Mid(dtmBootup, 7, 2) & "/" & Left(dtmBootup, 4) _ 
	& " " & Mid (dtmBootup, 9, 2) & ":" & Mid(dtmBootup, 11, 2) & ":" & Mid(dtmBootup, 13, 2))
End Function

' Check if msi package already installed
Function ChkPkgAlreadyInstalled
	Call GetMSIInfo("GUID", PRODUCTCODE, Null, Null)
	If Not(IsNull(GUID) Or IsEmpty(GUID)) Then
		sFound = Now & "__ Found " & AppName & " v" & MSIver & " already installed."
		sAlreadyInst = "Yes"
	Else
		Call GetMSIInfo("Name", "UniversalForwarder", Null, "InString")
		If Not(IsNull(GUID) Or IsEmpty(GUID)) Then
			If MSIver < VERSION Then
				If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
				sFound = Now & "__ Found " & AppName & " v" & MSIver & " installed, which is older than the current package version of " & VERSION & "."
				sAlreadyInst = "Upgrade"
			ElseIf MSIver > VERSION Then
				If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
				sFound = Now & "__ Found " & AppName & " v" & MSIver & " installed, which is newer than the version this script is coded to handle. Update script! Quiting."
				WSHLog "Warning", "Found installed version to be " & MSIver & ", which is newer than the version this script is coded to handle. Update script! Quiting."
				WScript.Quit
			End If
		Else
			If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
			DebugLog.WriteLine(Now & "__ No current or prior msi installations where found, going to check existence of service just in case.")
			Dim ChkSVC, sExePath, ExePathKEY
			ChkSVC = CheckService(sSVCName, "NULL", "NULL", "NoCheck", "NULL", "Required")
			If ChkSVC = "DoesntExist" Then
				DebugLog.WriteLine(Now & "__ Going to make one last check for well known areas of Splunk UF installation.")
				Call CheckforRemnants
			Else
				DebugLog.WriteLine(Now & "__ While no current or prior msi installations where found, the " & sSVCName & " service was found to exist. Remnants from a prior installation?")
				sExePath = "HKLM\System\CurrentControlSet\Services\" & sSVCName & "\ImagePath"
				ExePathKEY = GetRegData(sExePath, "{default}")
				If ExePathKEY = "{default}" Then
					DebugLog.WriteLine(Now & "__ Reg key " & sExePath & " does not exist. Dormant Service, remnants from a prior installation.")
					DebugLog.WriteLine(Now & "__ Going to check well known areas of Splunk UF installation.")
					Call CheckforRemnants
					sAlreadyInst = "Reinstall"			
				Else
					DebugLog.WriteLine(Now & "__ Found service registry key with path to executable to be " & sExePath & ". Remnants from a prior installation?")
					DebugLog.WriteLine(Now & "__ Going to check well known areas of Splunk UF installation.")
					Call CheckforRemnants
					sAlreadyInst = "Reinstall"
				End If
			End If
		End If
	End If
End Function

' Check if left over from prior install/corruption, etc.
Function CheckforRemnants
	On Error Resume Next
	Dim sPFN, sPD
	sPFN = "Splunk UF"
	sPD = oProcessEnv("ProgramFiles") & "\SplunkUniversalForwarder"
	'Check other 3 hidden services existance (sanity check)
	Dim sImagePath1, ImagePath1KEY, sImagePath2, ImagePath2KEY, sImagePath3, ImagePath3KEY, sCritical,	sCriticalFile
	sImagePath1 = "HKLM\SYSTEM\CurrentControlSet\Services\splknetdrv\ImagePath"
	ImagePath1KEY = GetRegData(sImagePath1, "{default}")
	If Not ImagePath1KEY = "{default}" Then
		DebugLog.WriteLine(Now & "__ Found reg key " & sImagePath1 & " exist. Remnants from a prior installation?")
		sAlreadyInst = "Reinstall"
	End If
	sImagePath2 = "HKLM\SYSTEM\CurrentControlSet\Services\splunkdrv\ImagePath"
	ImagePath2KEY = GetRegData(sImagePath2, "{default}")
	If Not ImagePath2KEY = "{default}" Then
		DebugLog.WriteLine(Now & "__ Found reg key " & sImagePath2 & " exist. Remnants from a prior installation?")
		sAlreadyInst = "Reinstall"
	End If
	sImagePath3 = "HKLM\SYSTEM\CurrentControlSet\Services\SplunkMonitorNoHandle\ImagePath"
	ImagePath3KEY = GetRegData(sImagePath3, "{default}")
	If Not ImagePath3KEY = "{default}" Then
		DebugLog.WriteLine(Now & "__ Found reg key " & sImagePath3 & " exist. Remnants from a prior installation?")
		sAlreadyInst = "Reinstall"
	End If

	Dim sCheckPath1, f, fc
	sCheckPath1 = sPD
	If oFSO.FolderExists(sCheckPath1) Then
		Set f = oFSO.GetFolder(sCheckPath1)
		Set fc = f.Files
		If fc.Count > 0 Then
			DebugLog.WriteLine(Now & "__ Found " & fc.Count & " files exist in " & sCheckPath1 & ". Remnants from a prior installation?")
		Else
			DebugLog.WriteLine(Now & "__ Found " & sCheckPath1 & " directory exists. Remnants from a prior installation.")
		End If
		sAlreadyInst = "Reinstall"
		Set f = Nothing
		Set fc = Nothing
	Else
		If (IsNull(sAlreadyInst) Or IsEmpty(sAlreadyInst)) Then sAlreadyInst = "No"
	End If
	On Error GoTo 0
End Function

' Uninstall MSI function, cProp is for when you need to have a custom condition in MSIUnistall Function to do something custom :) otherwise it doesnt matter what is passed.
Function MSIUninstall(sDisplayOptions)
	Dim sScriptUninst, MSICMDLINE, sMsiLog, iUnstVal
	sScriptUninst = "Uninstall-" & AppName & "-v" & MSIver
	Call Stamp
	sMsiLog = Chr(34) & sScriptsDir & "\" & sScriptUninst & "-MSI-" & altDate & "-" & altTime & ".log" & Chr(34)
	MSICMDLINE = "msiexec.exe REBOOT=ReallySuppress /x " & chr(34) & GUID & chr(34) & " " & sDisplayOptions & " /L*v " & sMsiLog
	DebugLog.WriteLine(Now & "__ Issuing uninstall commandline: " & MSICMDLINE)
	If sMSIDebugQA = "False" Then
		iUnstVal = oShell.Run(MSICMDLINE, 1, True)
		iMSIVal = iUnstVal
		If iMSIVal = 0 Or iMSIVal = 3010 Then
			DebugLog.WriteLine(Now & "__ MSI uninstallation completed, result code: " & iMSIVal)
		Else
			DebugLog.WriteLine(Now & "__ MSI uninstallation FAILED, result code: " & iMSIVal)
			WSHLog "CriticalFailure", "MSI uninstallation FAILED, result code: " & iMSIVal
		End If
	ElseIf sMSIDebugQA = "True" Then
		Dim sDebugTest
		sDebugTest = "NOTEPAD.EXE"
		iUnstVal = oShell.Run(sDebugTest, 1, True)
	End If
End Function


' ------   Wrapper 3.0.5 Functions/Subs section    -------

' Using WindowsInstaller engine get MSI ProductCode status Function
Function GetMSIInfo(sCond, sProperty1, sProperty2, sMatch) ' Condition = 'Name' or 'GUID' we will be providing / The name or GUID itself ' If name the type of match
	Call ResetMSIvalues
	On Error Resume Next
	Dim product, products, GetAppName
	Set oMSIinstaller = CreateObject("WindowsInstaller.Installer") : CheckError
	If oMSIinstaller Is Nothing Then
		iErrCode = "429"
		WSHLog "CriticalFailure", "Could not connect to WindowsInstaller.Installer" & Chr(13) & "Windows Installer Engine." & sMsg
	Else
		Set products = oMSIinstaller.Products : CheckError
		For Each product In products
			If UCASE(sCond) = "NAME" Then
				GetAppName = oMSIinstaller.ProductInfo(product, "ProductName")
				If UCASE(sMatch) = "EXACT" Then
					If UCASE(GetAppName) = UCASE(sProperty1) Then
						AppName = GetAppName
						GUID = product
						MSIver = oMSIinstaller.ProductInfo(product, "VersionString") : CheckError ' Installed
					End If
				Else
					If Not UCASE(sMatch) = "INSTR" Then
						If InStr(UCASE(GetAppName), UCASE(sProperty1)) And Not InStr(UCASE(GetAppName), UCASE(sMatch)) >0 Then
							AppName = GetAppName
							GUID = product
							MSIver = oMSIinstaller.ProductInfo(product, "VersionString") : CheckError ' Installed
						End If
					Else
						If InStr(UCASE(GetAppName), UCASE(sProperty1)) Then
							If InStr(UCASE(GetAppName), UCASE(sProperty2)) Then
								AppName = GetAppName
								GUID = product
								MSIver = oMSIinstaller.ProductInfo(product, "VersionString") : CheckError ' Installed
							End If
						End If
					End If
				End If
			ElseIf UCASE(sCond) = "GUID" Then
				If UCASE(product) = UCASE(sProperty1) Then
					AppName = oMSIinstaller.ProductInfo(product, "ProductName")
					GUID = product
					MSIver = oMSIinstaller.ProductInfo(product, "VersionString") : CheckError ' Installed
				End If
			End If
		Next
	End If
	Set oMSIinstaller = Nothing
	On Error GoTo 0
End Function

' Checks MSI Installer object errors Sub
Sub CheckError
	Dim message, errRec
	If Err = 0 Then Exit Sub
	message = Err.Source & " " & Hex(Err) & ": " & Err.Description
	If Not oMSIinstaller Is Nothing Then
		Set errRec = oMSIinstaller.LastErrorRecord
		If Not errRec Is Nothing Then message = message & ": " & errRec.FormatText
	End If
	iErrCode = Err.Number
	WSHLog "CriticalFailure", message  & ". " & sMsg
End Sub

' Reset MSI Values Sub
Sub ResetMSIvalues
	AppName = Null
	GUID = Null
	MSIver = Null
End Sub

' Check state of process(es), or Kill Process(es) Function
Function CheckProcess(pCond, pName, pMatch, action, sleeptime) ' Begins, Like, or Exact / %ProcessName / commandline match / Kill or Check
	On Error Resume Next
	Dim Process, oProcess, iCount
	If pCond = "Begins" Then
		Set Process = oWMI.ExecQuery("SELECT Name FROM Win32_Process WHERE Name LIKE '" & pName & "%'")
	ElseIf pCond = "Like" Then
		Set Process = oWMI.ExecQuery("SELECT Name FROM Win32_Process WHERE Name LIKE '%" & pName & "%'")
	ElseIf pCond = "Exact" Then
		Set Process = oWMI.ExecQuery("SELECT Name FROM Win32_Process WHERE Name ='" & pName & "'")
	End If
	If Process.Count = 0 Then
		CheckProcess = "notrunning" '"stopped"
	Else
		CheckProcess = "started"
		iCount = 1
		If action = "Kill" Then
			For Each oProcess In Process
				If Not IsNull(pMatch) Then
					If InStr(UCase(oProcess.CommandLine), UCase(pMatch)) Then
						oProcess.Terminate()
						If iCount < 2 Then
							DebugLog.WriteLine(Now & "__ Terminated: " & oProcess.Name & " process, ID: " & oProcess.ProcessId & " , CMDLine: " & oProcess.CommandLine)
						ElseIf iCount => 2 Then
							DebugLog.WriteLine(Now & "__ Terminated: " & oProcess.Name & " process, #" & iCount & ", ID: " & oProcess.ProcessId & " , CMDLine: " & oProcess.CommandLine)
						End If
					End If
				Else
					oProcess.Terminate()
					If iCount < 2 Then
						DebugLog.WriteLine(Now & "__ Terminated: " & oProcess.Name & " process, ID: " & oProcess.ProcessId & " , CMDLine: " & oProcess.CommandLine)
					ElseIf iCount => 2 Then
						DebugLog.WriteLine(Now & "__ Terminated: " & oProcess.Name & " process, #" & iCount & ", ID: " & oProcess.ProcessId & " , CMDLine: " & oProcess.CommandLine)
					End If
					iCount = iCount + 1
				End If
			Next
			WScript.Sleep sleeptime ' sleep to release files to be deleted. 5000 equals 5 seconds.
		Else
			' Process Audit mode
			For Each oProcess In Process
				If iCount < 2 Then
					DebugLog.WriteLine(Now & "__ Process found running: " & oProcess.Name & " process, ID: " & oProcess.ProcessId & " , CMDLine: " & oProcess.CommandLine)
				ElseIf iCount => 2 Then
					DebugLog.WriteLine(Now & "__ Process found running: " & oProcess.Name & " process, #" & iCount & ", ID: " & oProcess.ProcessId & " , CMDLine: " & oProcess.CommandLine)
				End If
			Next                                     
		End If
	End If
	On Error GoTo 0
End Function

' Check state of Service and manipulate it Function
Function CheckService(Name, Startup, Startup2, Status, DelayedAutoStart, Required)
	On Error Resume Next
	Dim oWin32Service, iErrDesc
	Set oWin32Service = GetObject("winmgmts:\\.\root\cimv2:Win32_Service")
	If Err.Number <> 0 Then
		iErrCode = Err.Number
		iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
		If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
		DebugLog.WriteLine(Now & "__ Unable to connect to WMI namespace \root\cimv2:Win32_Service. ")
		WSHLog "CriticalFailure", "Unable to connect to WMI namespace \root\cimv2:Win32_Service. Error code: " & iErrDesc
	End If
	Dim oSvc, sStartMode, sState, iMode, sStartMode2, iState, sState2, sExitCode, sSVCKey, SVCKey
	Dim sleepDur, SleepTime, iSleepDur
	SleepTime = "1000"
	iSleepDur = "3"
	Set oSvc = Getobject("winmgmts:root\cimv2:Win32_Service.Name='" & Name & "'")
	If Err.Number <> 0 Then
		If UCASE(Required) = "REQUIRED" Then
			If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
			DebugLog.WriteLine(Now & "__ Service: " & Name & ", does not exist on this system and is a mandatory service.")
			'WSHLog "CriticalFailure", "Service: " & Name & ", does not exist on this system and is a mandatory service."
			CheckService = "DoesntExist"
			Exit Function
		Else
			If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
			DebugLog.WriteLine(Now & "__ Service: " & Name & ", does not exist on this system")
			Exit Function
		End If
	Else
		sStartMode = oSvc.StartMode
		sState = oSvc.State
		If Not UCase(Startup) = "NULL" Then
			If sStartMode <> Startup Then
				iMode = oSvc.ChangeStartMode(Startup2)
				sExitCode = ResolveSVCcode(iMode)
				Set oSvc = Getobject("winmgmts:root\cimv2:Win32_Service.Name='" & Name & "'")
				sStartMode2 = oSvc.StartMode
				sState = oSvc.State
				If sStartMode2 <> Startup Then
					If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
					DebugLog.WriteLine(Now & "__ Failed to change Service: " & Name & ", from " & sStartMode & " to " & Startup2 & " (" & sExitCode & ")")
					WSHLog "Warning", "Failed to change Service: " & Name & ", from " & sStartMode & " to " & Startup2 & " (" & sExitCode & ")"
				Else
					If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
					DebugLog.WriteLine(Now & "__ Service: " & Name & ", was successfully changed from " & sStartMode & " to " & Startup2)
				End If
			Else
				If IsObject(DebugLog) Then DebugLog.WriteLine(Now & "__ Service: " & Name & ", found startup type already set to: " & sStartMode)
			End If
		End If
		sleepDur = 0
		If Not Status = "NoCheck" Then
			If Status = "Stopped" Then
				If sState <> Status Then                                                               
					iState = oSvc.StopService()
					sExitCode = ResolveSVCcode(iState)
					Do Until sState2 = "Stopped" Or sState2 = "Exceeded Wait Time"
						Wscript.Sleep SleepTime
						Set oSvc = Getobject("winmgmts:root\cimv2:Win32_Service.Name='" & Name & "'")
						sState2 = oSvc.State
						sleepDur = sleepDur + 1
						If sleepDur = iSleepDur Then
							sState2 = "Exceeded Wait Time" ' to get out of loop
						End If
					Loop
					If sleepDur = iSleepDur Then
						If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
						DebugLog.WriteLine(Now & "__ Service: " & Name & ", was found " & sState & "; attempt to stop the service failed OR Wait Time expired! (" & sExitCode & ")")
						WSHLog "Warning", "Service: " & Name & ", was found " & sState & "; attempt to stop the service failed OR Wait Time expired! (" & sExitCode & ")"
					Else
						If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
						DebugLog.WriteLine(Now & "__ Service: " & Name & ", was found " & sState & "; attempt to stop the service Succeeded.")
					End If
				End If
			ElseIf Status = "Running" Then
				If sState <> Status Then
					iState = oSvc.StartService()
					sExitCode = ResolveSVCcode(iState)
					Do Until sState2 = "Running" Or sState2 = "Exceeded Wait Time"
						WScript.Sleep SleepTime
						Set oSvc = Getobject("winmgmts:root\cimv2:Win32_Service.Name='" & Name & "'")
						sState2 = oSvc.State
						sleepDur = sleepDur + 1
						If sleepDur = iSleepDur Then
							sState2 = "Exceeded Wait Time" ' to get out of loop
						End If
					Loop
					If sleepDur = iSleepDur Then
						If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
						DebugLog.WriteLine(Now & "__ Service: " & Name & ", was found " & sState & "; attempt to start the service failed OR Wait Time expired! (" & sExitCode & ")")
						CheckService = "FailedtostartService"
						WSHLog "Warning", "Service: " & Name & ", was found " & sState & "; attempt to start the service failed OR Wait Time expired! (" & sExitCode & ")"
					Else
						If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
						DebugLog.WriteLine(Now & "__ Service: " & Name & ", was found " & sState & "; attempt to start the service Succeeded.")
						CheckService = "ServiceStarted"
					End If
				End If
			End If
		End If
		If DelayedAutoStart = "Delayed" Then
			sSVCKey = "HKLM\SYSTEM\CurrentControlSet\Services\" & Name & "\DelayedAutoStart"
			SVCKey = GetRegData(sSVCKey, "{default}")
			If SVCKey = "{default}" Then
				oShell.RegWrite sSVCKey, "1", "REG_DWORD"
				If Err.Number <> 0 Then
					If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
					DebugLog.WriteLine(Now & "__ Found " & sSVCKey & " missing, could not create reg Key with a value of 1 (Delayed Start).")
					WSHLog "Warning", "Found " & sSVCKey & " missing, could not create reg Key with a value of 1 (Delayed Start)."
				Else
					If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
					DebugLog.WriteLine(Now & "__ Successfully created " & sSVCKey & ", with value of 1 (Delayed Start).")
				End If
			ElseIf Not SVCKey = "1" Then
				oShell.RegWrite sSVCKey, "1", "REG_DWORD"
				If Err.Number <> 0 Then
					iErrCode = Err.Number
					iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
					If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
					DebugLog.WriteLine(Now & "__ Found " & sSVCKey & " set to " & SVCKey & ", was not able to change it to a value of 1 (Delayed Start). Error code: " & iErrDesc)
					WSHLog "Warning", "Found " & sSVCKey & " set to " & SVCKey & ", was not able to change it to a value of 1 (Delayed Start). Error code: " & iErrDesc
				Else
					If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
					DebugLog.WriteLine(Now & "__ Successfully changed " & sSVCKey & ", with value of 1 (Delayed Start).")
				End If
			End If
		End If
	End If
	On Error GoTo 0
End Function

' Resolve Exit Code to WMI Service Change
Function ResolveSVCcode(svccode)
	Select Case svccode
		Case 0 : ResolveSVCcode = "Success"
		Case 1 : ResolveSVCcode = "Not Supported"
		Case 2 : ResolveSVCcode = "Access Denied"
		Case 3 : ResolveSVCcode = "Dependent Services Running"
		Case 4 : ResolveSVCcode = "Invalid Service Control"
		Case 5 : ResolveSVCcode = "Service Cannot Accept Control"
		Case 6 : ResolveSVCcode = "Service Not Active"
		Case 7 : ResolveSVCcode = "Service Request Timeout"
		Case 8 : ResolveSVCcode = "Unknown Failure"
		Case 9 : ResolveSVCcode = "Path Not Found"
		Case 10 : ResolveSVCcode = "Service Already Running"
		Case 11 : ResolveSVCcode = "Service Database Locked"
		Case 12 : ResolveSVCcode = "Service Dependency Deleted"
		Case 13 : ResolveSVCcode = "Service Dependency Failure"
		Case 14 : ResolveSVCcode = "Service Disabled"
		Case 15 : ResolveSVCcode = "Service Logon Failed"
		Case 16 : ResolveSVCcode = "Service Marked For Deletion"
		Case 17 : ResolveSVCcode = "Service No Thread"
		Case 18 : ResolveSVCcode = "Status Circular Dependency"
		Case 19 : ResolveSVCcode = "Status Duplicate Name"
		Case 20 : ResolveSVCcode = "Status Invalid Name"
		Case 21 : ResolveSVCcode = "Status Invalid Parameter"
		Case 22 : ResolveSVCcode = "Status Invalid Service Account"
		Case 23 : ResolveSVCcode = "Status Service Exists"
		Case 24 : ResolveSVCcode = "Service Already Paused"
		Case Else : ResolveSVCcode = svccode
	End Select
End Function

' Read Registry Key/Values Function
Function GetRegData(sRegKey, vDefault)
	On Error Resume Next
	Dim vReturn
	vReturn = oShell.RegRead(sRegKey)
	If Err.Number <> 0 Then
		GetRegData = vDefault
		Err.Clear
	Else
		GetRegData = vReturn
	End If
	On Error GoTo 0
End Function

' Will delete any regkey and it subkeys Sub
Sub DeleteRegKeys(HIVE, sHive, sKeyPath)
	On Error Resume Next
	Const HKEY_CLASSES_ROOT = &H80000000: Const HKEY_CURRENT_USER = &H80000001
	Const HKEY_LOCAL_MACHINE = &H80000002: Const HKEY_USERS = &H80000003
	Const HKEY_CURRENT_CONFIG = &H80000005: Const HKEY_DYN_DATA = &H80000006
	Dim oReg, aSubkeys, sSubkey, iReturn
	Select Case sHive
		Case "HKCR": sHive = &H80000000
		Case "HKCU": sHive = &H80000001
		Case "HKLM": sHive = &H80000002
		Case "HKU": sHive = &H80000003
		Case "HKCC": sHive = &H80000004
		Case "HKDD": sHive = &H80000005
	End Select
	If sHive = "" Then sHive = HKEY_LOCAL_MACHINE
	Set oReg = GetObject("winmgmts:\\.\root\default:StdRegProv")
	oReg.EnumKey sHive, sKeyPath, aSubkeys
	If IsArray(aSubkeys) Then
		For Each sSubkey In aSubkeys
			DeleteRegKeys HIVE, sHive, sKeyPath & "\" & sSubkey
		Next
	End If
	iReturn = oReg.DeleteKey(sHive, sKeyPath)
	If iReturn = 0 Then
		DebugLog.WriteLine(Now & "__ Succeeded deleting: " & HIVE & "\" & sKeyPath)
	Else
		DebugLog.WriteLine(Now & "__ Failed deleting: " & HIVE & "\" & sKeyPath)
		WSHLog "Warning", "Failed deleting: " & HIVE & "\" & sKeyPath
	End If
	On Error GoTo 0
End Sub

Sub RegKeyCheck(sRegKey, Hive, HiveDupe)
	Dim sHive
	Select Case Hive
		Case "HKCR": sHive = "HKEY_CLASSES_ROOT"
		Case "HKCU": sHive = "HKEY_CURRENT_USER"
		Case "HKLM": sHive = "HKEY_LOCAL_MACHINE"
		Case "HKU": sHive = "HKEY_USERS"
		Case "HKCC": sHive = "HKEY_CURRENT_CONFIG"
		Case "HKDD": sHive = "HKEY_DYN_DATA"
	End Select
	On Error Resume Next
	Dim sCheck
	sCheck = oShell.RegRead(sHive & "\" & sRegKey & "\")
	If Err.Number = 0 Then
		DebugLog.WriteLine(Now & "__ Found " & sHive & "\" & sRegKey)
		Call DeleteRegKeys(Hive, HiveDupe, sRegKey)
	End If
	On Error GoTo 0
End Sub

' Get what OS, CSD version are we working with
Function GetOSInfo
	' Get what OS, CSD version are we working with
	On Error Resume Next
	Dim sPN, sCSDVer
	sPN = "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName"
	ProductName = GetRegData(sPN, "{default}")
	If ProductName = "{default}" Then
		iErrCode = "53"
		DebugLog.WriteLine(Now & "__ GetOSInfo function failed to read reg Key: " & sPN)
		WSHLog "CriticalFailure", "GetOSInfo function failed to read reg Key: " & sPN
	ElseIf ProductName = "" Then
		iErrCode = "53"
		DebugLog.WriteLine(Now & "__ GetOSInfo- function found a Null value in reg Value: " & sPN)
		WSHLog "CriticalFailure", "GetOSInfo- function found a Null value in reg Value: " & sPN
	End If
	If InStr(UCase(ProductName), "SERVER") Then
		IsServer = "True"	
		If Not oFSO.FileExists(oProcessEnv("SYSTEMROOT") & "\explorer.exe") Then
			IsServerCore = "True"
		End If
	End If
	sCSDVer = "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CSDVersion"
	CSDver = GetRegData(sCSDVer, "{default}")
	If CSDver = "{default}" Then CSDver = "RTM"
	s64Bit = "0"
	If oFSO.FileExists(oProcessEnv("SYSTEMROOT") & "\SysWOW64\wscript.exe") Then
		s64Bit = "1"
	End If
	If s64Bit = "1" Then
		ProductName = ProductName & " x64"
	End If
	sMsg = sMsg & "|Hostname: " & sCN & "|OS: " & ProductName & ", " & CSDver & "." ' Do not remove this last & "." otherwise it wraps
	On Error GoTo 0
End Function

' Check if DC Function 
Function IsDC
	On Error Resume Next
	Dim DeviceInfo, oDomain
	Set DeviceInfo = oWMI.ExecQuery("SELECT DomainRole FROM Win32_ComputerSystem")
	If Err.Number = 0 Then
		For Each oDomain In DeviceInfo 
			If oDomain.DomainRole = 4 Or oDomain.DomainRole = 5 Then DC = "True"
		Next
	Else
		WSHLog "CriticalFailure", "Critical issue, could not connect to WMI, cimv2:Win32_ComputerSystem to obtain DomainRole information."
	End If
	Set DeviceInfo = Nothing
	On Error GoTo 0
End Function

' Get ID of who is running the script, as well as who is logged on (if anyone) Function
Function GetWhoIsRunningScript
	On Error Resume Next
	If sWMIFailed = "Failed" Then
		sMsg = sMsg & "|Script was executed utilizing account: (WMI not available) "
		sMsg = sMsg & "|Following account(s) are logged on during execution of script: (WMI not available) "
	Else
		Dim cProcessList, oProcess, cProperties, sNameOfUser, sUserDomain
		Set cProcessList = oWMI.ExecQuery("SELECT CommandLine,Name FROM Win32_Process WHERE " & "Name = 'cscript.exe' or Name = 'wscript.exe'")
		For Each oProcess in cProcessList
			If InStr(oProcess.CommandLine, Wscript.ScriptFullName) Then
				cProperties = oProcess.GetOwner(sNameOfUser,sUserDomain)
			End If
		Next
		If IsObject(DebugLog) Then DebugLog.WriteLine(Now & "__ Script was executed utilizing account: " & sUserDomain & "\" & sNameOfUser)
		sMsg = sMsg & "|Script was executed utilizing account: " & sUserDomain & "\" & sNameOfUser & "."	
	
		Dim cCS, oCS, LoggedInUser
		Set cCS = oWMI.ExecQuery("SELECT UserName FROM Win32_ComputerSystem")
		LoggedInUser = "NOONE"
		For Each oCS in cCS
			LoggedInUser = oCS.UserName
		Next
		If IsNull(LoggedInUser) Then
			If IsObject(DebugLog) Then DebugLog.WriteLine(Now & "__ Script detected the following account(s) are logged on during start of installation: No Logon detected")
			sMsg = sMsg & "|Following account(s) are logged on during execution of script: No Logon detected"
		Else
			If IsObject(DebugLog) Then DebugLog.WriteLine(Now & "__ Script detected the following account(s) are logged on during start of installation: " & LoggedInUser)
			sMsg = sMsg & "|Following account(s) are logged on during execution of script: " & LoggedInUser
		End If
	End If
	On Error GoTo 0
End Function

' Creates Corporate Engineering debug log (or append to existing log if run before) Function
Function CreateDebugLog(sCondition)
	If sCondition = "WriteLog" Then
		Call CreateDebugLogNow
	Else
		If (sCoreBlat <> "" Or sCoreBlat2 <> "" Or sCoreWMI <> "" Or sCoreInfo <> "" Or sCoreInfo2 <> "" Or sCoreInfo3 <> "") Then
			Call CreateDebugLogNow
		End If
	End If
End Function

Sub CreateDebugLogNow
	On Error Resume Next
	Const ForReading = 1 : Const ForWriting = 2 : Const ForAppending = 8
	Dim iErrDesc
	If NOT oFSO.FileExists(sDebugLog) Then
		Set DebugLog = oFSO.OpenTextFile(sDebugLog, ForWriting, True)
		If Err.Number <> 0 Then
			iErrCode = Err.Number
			iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
			Call GetWhoIsRunningScript
			WSHLog "CriticalFailure", "Attempt to create Debuglog: " &  sDebugLog & ", failed. Error code: " & iErrDesc
		End If
	Else ' Append to existing log
		Set DebugLog = oFSO.OpenTextFile(sDebugLog, ForAppending, True)
		If Err.Number <> 0 Then
			iErrCode = Err.Number
			iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
			Call GetWhoIsRunningScript
			WSHLog "CriticalFailure", "Attempt to append to Debuglog: " &  sDebugLog & ", failed. Error code: " & iErrDesc
		Else
			DebugLog.WriteLine(" ")
		End If
	End If
	WSHLog "Information", "Commencing installation of " & DEPLOYNAME & SIDE & RELEASE
	DebugLog.WriteLine(Now & "__ Commencing installation of " & DEPLOYNAME & SIDE & RELEASE & " on " & oProcessEnv("COMPUTERNAME"))
	DebugLog.WriteLine(Now & "__ Script/Path utilized: " & Wscript.ScriptFullName)
	If sCoreBlat <> "" Then	DebugLog.WriteLine(sCoreBlat)
	If sCoreBlat2 <> "" Then DebugLog.WriteLine(sCoreBlat2)
	If sCoreWMI <> "" Then DebugLog.WriteLine(sCoreWMI)
	If sCoreInfo <> "" Then DebugLog.WriteLine(sCoreInfo)
	If sCoreInfo2 <> "" Then DebugLog.WriteLine(sCoreInfo2)
	If sCoreInfo3 <> "" Then DebugLog.WriteLine(sCoreInfo3)
	Call GetWhoIsRunningScript
	On Error GoTo 0
End Sub

' Creates Corporate Engineering Logs directory(s) for script, package installation, and custom logging if they do not exist
Function CreateLogDirs
	If Not oFSO.FolderExists(sLogDir) Then Call CreateLogDir(sLogDir)
	If Not oFSO.FolderExists(sScriptsDir) Then Call CreateLogDir(sScriptsDir)
	If Not oFSO.FolderExists(sEmailDir) Then Call CreateLogDir(sEmailDir)
End Function

' Create Log directory's requested 
Sub CreateLogDir(sDir)
	On Error Resume Next
	Dim iErrDesc
	oFSO.CreateFolder(sDir)
	If Err.Number = 0 Then
		WSHLog "Success", sDir & " directory Created."
		If sDir = sLogDir Then sCoreInfo = Now & "__ " & sLogDir & " directory Created."
		If sDir = sScriptsDir Then sCoreInfo2 = Now & "__ " & sScriptsDir & " directory Created."
		If sDir = sEmailDir Then sCoreInfo3 = Now & "__ " & sEmailDir & " directory Created."
	Else
		iErrCode = Err.Number
		iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
		Call GetWhoIsRunningScript
		oProcessEnv("SEE_MASK_NOZONECHECKS") = 1
		WSHLog "CriticalFailure", "Could not create " & sDir & " directory, Error # " & iErrDesc
	End If
	On Error GoTo 0
End Sub

' Copy blat file to system to ensure email alerts are available
Function CopyBlat
	On Error Resume Next
	Dim fn, vTimeThis, sLenghtTM, iErrDesc : fn = "blat.exe"
	If Not oFSO.FileExists(sBlat) Then
		If oFSO.FileExists(sLib & fn) Then
			vTimeThis = Now
			oFSO.CopyFile sLib & fn, sSystem32 & fn, True
			If Err.Number = 0 Then
				sLenghtTM = DateDiffToWords(vTimeThis,Now)
				WSHLog "Success", "Copied " & fn & " successfully. Took: " & sLenghtTM & "."
				sCoreBlat2 = Now & "__ Copied " & fn & " successfully. Took: " & sLenghtTM & "."
				If sDebugBlat = "True" Then Email "Copied " & fn & " successfully", "Copied " & fn & " successfully. Took: " & sLenghtTM & "."
			Else
				iErrCode = Err.Number
				iErrDesc = CStr(Err.Number) & " " & Err.Description & "."
				sBlat = sLib & "blat.exe"
				oProcessEnv("SEE_MASK_NOZONECHECKS") = 1
				WSHLog "Failure", "Could not copy " & fn & " from " & sLib & " to: " & sSystem32 & ", Error # " & iErrDesc & ". Will continue with network copy... ||"
				oProcessEnv.Remove("SEE_MASK_NOZONECHECKS")
			End If
		Else
			sCoreBlat = Now & "__ Blat not found, not in: " & sSystem32 & ", nor in: " & sLib & " no email status will be available."
			WSHLog "Failure", "Blat not found, not in: " & sSystem32 & ", nor in: " & sLib & " no email status will be available."
		End If
	End If
	On Error GoTo 0
End Function

' Get AD domain Name
Function GetDomainName
	On Error Resume Next
	Dim Info
	Set Info = CreateObject("AdSystemInfo")
	If Err.Number <> 0 Then
		iErrCode = Err.Number	
		Call CreateLogDirs
		If Not IsObject(DebugLog) Then Call CreateDebugLog("WriteLog")
		WSHLog "CriticalFailure", "Failed to create object AdSystemInfo, error: " & iErrCode
	Else
		sDomFQDN = Info.DomainDNSName
	End If
	On Error GoTo 0
End Function

' WSH Application Event Log, logging Function
Function WSHLog(EventType, Desc)
	On Error Resume Next
	If EventType = "Information" Then oShell.LogEvent 4, sScript & Chr(13) & "------------------------------------------------------" & Chr(13) & Desc
	If EventType = "Success" Then oShell.LogEvent 0, sScript & Chr(13) & "------------------------------------------------------" & Chr(13) & Desc
	If EventType = "Warning" Then
		oShell.LogEvent 2, sScript & Chr(13) & "------------------------------------------------------" & Chr(13) & Desc
		WScript.Sleep 500
		If sCoreBlat = "" Then Email EventType, Desc & " " & sMsg
	End If
	If EventType = "Failure" Then
		oShell.LogEvent 1, sScript & Chr(13) & "------------------------------------------------------" & Chr(13) & Desc
		WScript.Sleep 500
		If sCoreBlat = "" Then Email EventType, Desc & " " & sMsg
	End If
	If EventType = "CriticalFailure" Then
		oShell.LogEvent 1, sScript & Chr(13) &    "------------------------------------------------------" & Chr(13) & Desc & " Script exiting..."
		WScript.Sleep 500
		If Not((IsNull(iMSIVal) Or IsEmpty(iMSIVal)) Or iMSIVal = 0 Or iMSIVal = 1030) Then
			If IsObject(DebugLog) Then DebugLog.WriteLine(Now & "__ Critical failure, exiting... Wrapper exit code: " & iMSIVal)
			sPilot = "True" ' Force attachment of debuglog since we have a critical failure
			Call Cleanup(sScript & " - " & EventType, Desc & "| |" & sMsg)
			WScript.Quit(iMSIVal)
		ElseIf Not(IsNull(iErrCode) Or IsEmpty(iErrCode)) Then
			If IsObject(DebugLog) Then DebugLog.WriteLine(Now & "__ Critical failure, exiting... Wrapper exit code : " & iErrCode)
			sPilot = "True" ' Force attachment of debuglog since we have a critical failure
			Call Cleanup(sScript & " - " & EventType, Desc & "| |" & sMsg)
			WScript.Quit(iErrCode)
		Else
			If IsObject(DebugLog) Then DebugLog.WriteLine(Now & "__ Critical failure exiting... Wrapper exit code  : " & Err.Number)
			sPilot = "True" ' Force attachment of debuglog since we have a critical failure
			Call Cleanup(sScript & " - " & EventType, Desc & "| |" & sMsg)
			WScript.Quit
		End If
	End If
	On Error GoTo 0
End Function

' EMail Results Function
Function Email(Subject, Body)
	On Error Resume Next
	Dim sTmpFile, sP1, sP2, iMail
	If Not(IsNull(sMailbox2) Or IsEmpty(sMailbox2)) Then
		sP1 = sMailbox1 & "," & sMailbox2
	Else
		sP1 = sMailbox1
	End If
	sTmpFile = sEmailDir & "\" & oFSO.GetTempName
	oFSO.CreateTextFile sTmpFile
	If Err.Number <> 0 Then
		sP2 = "-log " & Chr(34) & oProcessEnv("TEMP") & "\"
	Else
		oFSO.DeleteFile sTmpFile
		sP2 = "-log " & Chr(34) & sEmailDir & "\"
	End If

	Call Stamp
	If (sPilot = "True") And (IsObject(DebugLog)) Then
		iMail = oShell.Run(sBlat & " -body " & Chr(34) &_
		Body & Chr(34) & " -to " & sP1 & " -subject " & Chr(34) & Subject &_
		Chr(34) & " -server " & sRelayHost & " -f " & sCN & sFQDN & " -attacht " & Chr(34) & sDebugLog & Chr(34) & " -debug " & sP2 & sScript & "_" & altDate & "-" & altTime & ".log" & Chr(34) & " -try " & sTry, 2, True)
	Else
		iMail = oShell.Run(sBlat & " -body " & Chr(34) &_
		Body & Chr(34) & " -to " & sP1 & " -subject " & Chr(34) & Subject &_
		Chr(34) & " -server " & sRelayHost & " -f " & sCN & sFQDN & " -debug " & sP2 & sScript & "_" & altDate & "-" & altTime & ".log" & Chr(34) & " -try " & sTry, 2, True)
	End If
	On Error Goto 0
End Function

' Date/Time Stamping Function
Function Stamp
	On Error Resume Next
	Dim oSplit
	vDate = FormatDateTime(Now(), vbShortDate)
	altDate = Replace(Date, "/", "_")
	vTime = FormatDateTime(Now(), vbLongTime)
	altTime = Replace(Time, ":", ".")
	oSplit = Split(altTime)
	altTime = oSplit(0) & "." & oSplit(1)
	On Error GoTo 0
End Function

' Time into words Function
Function DateDiffToWords(d1, d2)
	Dim report, seconds
	report = ""
	seconds = abs(datediff("S", d1, d2))
	If seconds <= 0 Then
		report = "0 seconds"
	Else
		seconds = seconds mod (24*60*60)
		'divide by 3600 to get hours
		If seconds >= 3600 Then
			report = report & seconds\(3600) & " hour(s), "
		End If
		'use mod to get remaining seconds and divide to get minutes
		seconds = seconds mod (60*60)
		If seconds >= 60 Then
			report = report & seconds\(60) & " minute(s), "
		End If
		'use mod to get remaining seconds
		seconds = seconds Mod (60)
		report = report & seconds & " second(s)"
	End If
	DateDiffToWords = report
End Function

' Close up logs, objects, etc...
Function Cleanup(Subject, Body)
	' Close log(s)
	If IsObject(DebugLog) Then DebugLog.Close
	If (sPilot = "True") And (sCoreBlat = "") Then Email Subject, Body
	If oProcessEnv("SEE_MASK_NOZONECHECKS") = "1" Then oProcessEnv.Remove("SEE_MASK_NOZONECHECKS")
	
	'Clean Up
	Set oWMI = Nothing
	Set oProcessEnv = Nothing
	Set oFSO = Nothing
	Set oShell = Nothing
End Function

'' SIG '' Begin signature block
'' SIG '' MIITbgYJKoZIhvcNAQcCoIITXzCCE1sCAQExCzAJBgUr
'' SIG '' DgMCGgUAMGcGCisGAQQBgjcCAQSgWTBXMDIGCisGAQQB
'' SIG '' gjcCAR4wJAIBAQQQTvApFpkntU2P5azhDxfrqwIBAAIB
'' SIG '' AAIBAAIBAAIBADAhMAkGBSsOAwIaBQAEFOD0PSSC1prF
'' SIG '' zszbxykU+MlLNqY1oIIODDCCBBQwggL8oAMCAQICCwQA
'' SIG '' AAAAAS9O4VLXMA0GCSqGSIb3DQEBBQUAMFcxCzAJBgNV
'' SIG '' BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNh
'' SIG '' MRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9i
'' SIG '' YWxTaWduIFJvb3QgQ0EwHhcNMTEwNDEzMTAwMDAwWhcN
'' SIG '' MjgwMTI4MTIwMDAwWjBSMQswCQYDVQQGEwJCRTEZMBcG
'' SIG '' A1UEChMQR2xvYmFsU2lnbiBudi1zYTEoMCYGA1UEAxMf
'' SIG '' R2xvYmFsU2lnbiBUaW1lc3RhbXBpbmcgQ0EgLSBHMjCC
'' SIG '' ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJTv
'' SIG '' Zfi1V5+gUw00BusJH7dHGGrL8Fvk/yelNNH3iRq/nrHN
'' SIG '' EkFuZtSBoIWLZFpGL5mgjXex4rxc3SLXamfQu+jKdN6L
'' SIG '' Tw2wUuWQW+tHDvHnn5wLkGU+F5YwRXJtOaEXNsq5oIwb
'' SIG '' TwgZ9oExrWEWpGLmtECew/z7lfb7tS6VgZjg78Xr2AJZ
'' SIG '' eHf3quNSa1CRKcX8982TZdJgYSLyBvsy3RZR+g79ijDw
'' SIG '' Fwmnu/MErquQ52zfeqn078RiJ19vmW04dKoRi9rfxxRM
'' SIG '' 6YWy7MJ9SiaP51a6puDPklOAdPQD7GiyYLyEIACDG6Hu
'' SIG '' tHQFwSmOYtBHsfrwU8wY+S47+XB+tCUCAwEAAaOB5TCB
'' SIG '' 4jAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB
'' SIG '' /wIBADAdBgNVHQ4EFgQURtg+/9zjvv+D5vSFm7DdatYU
'' SIG '' qcEwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUH
'' SIG '' AgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3Jl
'' SIG '' cG9zaXRvcnkvMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6
'' SIG '' Ly9jcmwuZ2xvYmFsc2lnbi5uZXQvcm9vdC5jcmwwHwYD
'' SIG '' VR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJ
'' SIG '' KoZIhvcNAQEFBQADggEBAE5eVpAeRrTZSTHzuxc5KBvC
'' SIG '' Ft39QdwJBQSbb7KimtaZLkCZAFW16j+lIHbThjTUF8xV
'' SIG '' OseC7u+ourzYBp8VUN/NFntSOgLXGRr9r/B4XOBLxRjf
'' SIG '' OiQe2qy4qVgEAgcw27ASXv4xvvAESPTwcPg6XlaDzz37
'' SIG '' Dbz0xe2XnbnU26UnhOM4m4unNYZEIKQ7baRqC6GD/Sjr
'' SIG '' 2u8o9syIXfsKOwCr4CHr4i81bA+ONEWX66L3mTM1fsua
'' SIG '' irtFTec/n8LZivplsm7HfmX/6JLhLDGi97AnNkiPJm87
'' SIG '' 7k12H3nD5X+WNbwtDswBsI5//1GAgKeS1LNERmSMh08W
'' SIG '' YwcxS2Ow3/MwggSfMIIDh6ADAgECAhIRIdaZp2SXPvH4
'' SIG '' Qn7pGcxTQRQwDQYJKoZIhvcNAQEFBQAwUjELMAkGA1UE
'' SIG '' BhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex
'' SIG '' KDAmBgNVBAMTH0dsb2JhbFNpZ24gVGltZXN0YW1waW5n
'' SIG '' IENBIC0gRzIwHhcNMTYwNTI0MDAwMDAwWhcNMjcwNjI0
'' SIG '' MDAwMDAwWjBgMQswCQYDVQQGEwJTRzEfMB0GA1UEChMW
'' SIG '' R01PIEdsb2JhbFNpZ24gUHRlIEx0ZDEwMC4GA1UEAxMn
'' SIG '' R2xvYmFsU2lnbiBUU0EgZm9yIE1TIEF1dGhlbnRpY29k
'' SIG '' ZSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
'' SIG '' CgKCAQEAsBeuotO2BDBWHlgPse1VpNZUy9j2czrsXV6r
'' SIG '' Jf02pfqEw2FAxUa1WVI7QqIuXxNiEKlb5nPWkiWxfSPj
'' SIG '' BrOHOg5D8NcAiVOiETFSKG5dQHI88gl3p0mSl9RskKB2
'' SIG '' p/243LOd8gdgLE9YmABr0xVU4Prd/4AsXximmP/Uq+yh
'' SIG '' RVmyLm9iXeDZGayLV5yoJivZF6UQ0kcIGnAsM4t/aIAq
'' SIG '' taFda92NAgIpA6p8N7u7KU49U5OzpvqP0liTFUy5LauA
'' SIG '' o6Ml+6/3CGSwekQPXBDXX2E3qk5r09JTJZ2Cc/os+XKw
'' SIG '' qRk5KlD6qdA8OsroW+/1X1H0+QrZlzXeaoXmIwRCrwID
'' SIG '' AQABo4IBXzCCAVswDgYDVR0PAQH/BAQDAgeAMEwGA1Ud
'' SIG '' IARFMEMwQQYJKwYBBAGgMgEeMDQwMgYIKwYBBQUHAgEW
'' SIG '' Jmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9z
'' SIG '' aXRvcnkvMAkGA1UdEwQCMAAwFgYDVR0lAQH/BAwwCgYI
'' SIG '' KwYBBQUHAwgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov
'' SIG '' L2NybC5nbG9iYWxzaWduLmNvbS9ncy9nc3RpbWVzdGFt
'' SIG '' cGluZ2cyLmNybDBUBggrBgEFBQcBAQRIMEYwRAYIKwYB
'' SIG '' BQUHMAKGOGh0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5j
'' SIG '' b20vY2FjZXJ0L2dzdGltZXN0YW1waW5nZzIuY3J0MB0G
'' SIG '' A1UdDgQWBBTUooRKOFoYf7pPMFC9ndV6h9YJ9zAfBgNV
'' SIG '' HSMEGDAWgBRG2D7/3OO+/4Pm9IWbsN1q1hSpwTANBgkq
'' SIG '' hkiG9w0BAQUFAAOCAQEAj6kakW0EpjcgDoOW3iPTa24f
'' SIG '' bt1kPWghIrX4RzZpjuGlRcckoiK3KQnMVFquxrzNY46z
'' SIG '' PVBI5bTMrs2SjZ4oixNKEaq9o+/Tsjb8tKFyv22XY3mM
'' SIG '' RLxwL37zvN2CU6sa9uv6HJe8tjecpBwwvKu8LUc235Ig
'' SIG '' A+hxxlj2dQWaNPALWVqCRDSqgOQvhPZHXZbJtsrKnbem
'' SIG '' uuRQ09Q3uLogDtDTkipbxFm7oW3bPM5EncE4Kq3jjb3N
'' SIG '' CXcaEL5nCgI2ZIi5sxsm7ueeYMRGqLxhM2zPTrmcuWrw
'' SIG '' nzf+tT1PmtNN/94gjk6Xpv2fCbxNyhh2ybBNhVDygNId
'' SIG '' BvVYBAexGDCCBU0wggQ1oAMCAQICEAPq4x/DNeCiI9mC
'' SIG '' 5DlK/ZUwDQYJKoZIhvcNAQELBQAwcjELMAkGA1UEBhMC
'' SIG '' VVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UE
'' SIG '' CxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGln
'' SIG '' aUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmlu
'' SIG '' ZyBDQTAeFw0xODAzMjIwMDAwMDBaFw0yMTAzMjUxMjAw
'' SIG '' MDBaMIGJMQswCQYDVQQGEwJVUzERMA8GA1UECBMITmV3
'' SIG '' IFlvcmsxETAPBgNVBAcTCE5ldyBZb3JrMSkwJwYDVQQK
'' SIG '' EyBUaGUgT3JjaGFyZCBFbnRlcnByaXNlcyBOWSwgSW5j
'' SIG '' LjEpMCcGA1UEAxMgVGhlIE9yY2hhcmQgRW50ZXJwcmlz
'' SIG '' ZXMgTlksIEluYy4wggEiMA0GCSqGSIb3DQEBAQUAA4IB
'' SIG '' DwAwggEKAoIBAQC+uBrLcB6HSH12Fw3iQk0wnrBMR/Xm
'' SIG '' yH+oInoXTnQhhGhTle6PWioUUp4b7K6v1o5t/7oqqeU1
'' SIG '' TlZhFrXw20wGa0X5B2U07eeRyB9jWMyeDalbWPazUlfo
'' SIG '' gmtiGnHUTbj1+MtjtnIb2eVv7umcNoi7qhPzJvVMDIyC
'' SIG '' J4OYi6pIfV+nVjuGizGK3Ep43fj8eM1rpvpF4qxsPt/8
'' SIG '' mGgcbZVKVPERkezu8PhnqsQq6BKp6ncq+BbKaolzwRcV
'' SIG '' i7ZZzmpsnRFKU6jE06s0ptBmUCl/7WY69qMdO0Tu4RNY
'' SIG '' ItuihrFaWL2WLdjPANvTFG2xL2DgIz4LEWgSUVOu4aSw
'' SIG '' g39XAgMBAAGjggHFMIIBwTAfBgNVHSMEGDAWgBRaxLl7
'' SIG '' KgqjpepxA8Bg+S32ZXUOWDAdBgNVHQ4EFgQUFWb1jhPM
'' SIG '' z9PmvFrOw3FSTHHXyswwDgYDVR0PAQH/BAQDAgeAMBMG
'' SIG '' A1UdJQQMMAoGCCsGAQUFBwMDMHcGA1UdHwRwMG4wNaAz
'' SIG '' oDGGL2h0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEy
'' SIG '' LWFzc3VyZWQtY3MtZzEuY3JsMDWgM6Axhi9odHRwOi8v
'' SIG '' Y3JsNC5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLWNz
'' SIG '' LWcxLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG/WwDATAq
'' SIG '' MCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy
'' SIG '' dC5jb20vQ1BTMAgGBmeBDAEEATCBhAYIKwYBBQUHAQEE
'' SIG '' eDB2MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp
'' SIG '' Y2VydC5jb20wTgYIKwYBBQUHMAKGQmh0dHA6Ly9jYWNl
'' SIG '' cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJBc3N1
'' SIG '' cmVkSURDb2RlU2lnbmluZ0NBLmNydDAMBgNVHRMBAf8E
'' SIG '' AjAAMA0GCSqGSIb3DQEBCwUAA4IBAQAgdQ4jSO4z+O79
'' SIG '' 4AlCpzGIOmn8XT2WTDPXg5b5lPg3Z22YMQ5JHmRzWXax
'' SIG '' mxFAhD8kCSPGhL+MfIJMZt9hTbdM8WUinqKLNvbVDiIK
'' SIG '' O1H9Vnwz5VJ03qGRExixZOiULeeNDmj6kh4KcqFtzio0
'' SIG '' M/4GARMYiwyBg1CNlD59Jvz3RzFZugm3K+yXU1JlznMJ
'' SIG '' 8QoY0MWHsiHV/nJssNnMWCpvR7S0wC5pSn3DXeS7XVma
'' SIG '' SAc3xavwCg5sJG3LS2LKwx12ksbj+mfz+t2RqQIE5iFz
'' SIG '' 81EVhK7qbF8cbRKhgtcqbCjqr3dsj4lfMpe/+OcXR7DI
'' SIG '' wWGGyquVUv0vqiaTph2zMYIEzjCCBMoCAQEwgYYwcjEL
'' SIG '' MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IElu
'' SIG '' YzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8G
'' SIG '' A1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENv
'' SIG '' ZGUgU2lnbmluZyBDQQIQA+rjH8M14KIj2YLkOUr9lTAJ
'' SIG '' BgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAA
'' SIG '' oQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAc
'' SIG '' BgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkq
'' SIG '' hkiG9w0BCQQxFgQUbAvUQGVKrUuyUVO0S178q9M0dZgw
'' SIG '' DQYJKoZIhvcNAQEBBQAEggEABBX52RT0PWCj1d0MIyIu
'' SIG '' AQyBIqg/UxGeKx+l3jQsnbkPDBH3mahNclbjoKnml4O7
'' SIG '' ZQYGzFCwdXyhsNmfimFwYgAUUgES+TRlNR0LMuVlWcAF
'' SIG '' rzftICDu8yPBBx86JYZe93b0qw2VpIestTRMU+iHoElX
'' SIG '' LJHwThQLjA+JdG+5YeZkV7V/6noYMwDCC5XqE7szBUds
'' SIG '' HqBtYcXHoEs6L0zCXSjYeyXXRFlyKQ6SxhIl5tcnRkES
'' SIG '' aV9TynIl4nMEV41OMp4LGMA38teZ2v9kkMulrrqqRwDI
'' SIG '' maXa38uRFd6v+yautWz4xjEQapM5nGdHA+ixXc2xtmnK
'' SIG '' 2uRVIUY1vo6Zd6GCAqIwggKeBgkqhkiG9w0BCQYxggKP
'' SIG '' MIICiwIBATBoMFIxCzAJBgNVBAYTAkJFMRkwFwYDVQQK
'' SIG '' ExBHbG9iYWxTaWduIG52LXNhMSgwJgYDVQQDEx9HbG9i
'' SIG '' YWxTaWduIFRpbWVzdGFtcGluZyBDQSAtIEcyAhIRIdaZ
'' SIG '' p2SXPvH4Qn7pGcxTQRQwCQYFKw4DAhoFAKCB/TAYBgkq
'' SIG '' hkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJ
'' SIG '' BTEPFw0xODA1MjQyMDE4NDBaMCMGCSqGSIb3DQEJBDEW
'' SIG '' BBTh1lXFKFraOzMONc+8hJrtiW2zQzCBnQYLKoZIhvcN
'' SIG '' AQkQAgwxgY0wgYowgYcwgYQEFGO4L6th9YOQlpUFCwAk
'' SIG '' nFApM+x5MGwwVqRUMFIxCzAJBgNVBAYTAkJFMRkwFwYD
'' SIG '' VQQKExBHbG9iYWxTaWduIG52LXNhMSgwJgYDVQQDEx9H
'' SIG '' bG9iYWxTaWduIFRpbWVzdGFtcGluZyBDQSAtIEcyAhIR
'' SIG '' IdaZp2SXPvH4Qn7pGcxTQRQwDQYJKoZIhvcNAQEBBQAE
'' SIG '' ggEAMUWdMotInPMPUX+OA7ZOqR3PXtE2/gcjxKrXq50Y
'' SIG '' 6RbxXkzLG/eFocNv3YSqMU2F2nnSOX580CZtWC+B4hUe
'' SIG '' b+gJ62YXKAX7wAe3987o8aA4rFBoB9EROvksNnMzS1wB
'' SIG '' w7ocMAD86p1gZ7TQnYJtR4r3urSC7j41/K1KJVfwp9VL
'' SIG '' QfaKzEqlQ7xYnbqpvYC62b2YghEsJkfKy0JYTwgbnGgm
'' SIG '' Tk8eJ/gsn+xauVEad1egCDanz+1pSjT/pOtFfA+TFYCl
'' SIG '' ruBMjEA+SG7b9RabAEWC6zeoqaeW4cIRaRCFNsaGsYul
'' SIG '' 6t2qcR8PQMN8EWUHwPSGyzJ0BcF6o/62XA8kLA==
'' SIG '' End signature block
