ConfigMgr 2007 Monitor Site Maintenance Tasks

SMSv4_Monitor_Site_Maintenance_Tasks (WriteActionModuleType)

Monitors all SMS Site Maintenance Tasks

Element properties:

TypeWriteActionModuleType
IsolationAny
AccessibilityInternal
RunAsDefault
InputTypeSystem.BaseData
Comment{19EFCE1A-E1AA-443E-9A64-9CA202FB72C3}

Member Modules:

ID Module Type TypeId RunAs 
RunScriptAction WriteAction System.Mom.BackwardCompatibility.ScriptResponse Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
MaximumTaskDurationstring$Config/Parameters/MaximumTaskDuration$MaximumTaskDurationThe expected maximum duration, in seconds, for execution of a task.

Source Code:

<WriteActionModuleType ID="SMSv4_Monitor_Site_Maintenance_Tasks" Accessibility="Internal" Comment="{19EFCE1A-E1AA-443E-9A64-9CA202FB72C3}">
<Configuration>
<IncludeSchemaTypes>
<SchemaType>MomBackwardCompatibility!System.Mom.BackwardCompatibility.AlertGenerationSchema</SchemaType>
</IncludeSchemaTypes>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="AlertGeneration" type="AlertGenerationType"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="InvokerType" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="Parameters" minOccurs="0">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="MaximumTaskDuration" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="MaximumTaskDuration" Selector="$Config/Parameters/MaximumTaskDuration$" ParameterType="string"/>
</OverrideableParameters>
<ModuleImplementation>
<Composite>
<MemberModules>
<WriteAction ID="RunScriptAction" TypeID="MomBackwardCompatibility!System.Mom.BackwardCompatibility.ScriptResponse">
<AlertGeneration>$Config/AlertGeneration$</AlertGeneration>
<InvokerType>$Config/InvokerType$</InvokerType>
<Body><Script>
'*******************************************************************************
' Script Name - ConfigMgr 2007 Monitor Site Maintenance Tasks
'
' Purpose - Monitor all site maintenance tasks in the SMS Site Database.
' Raise an event when a task runs beyond a configured duration
' and when it completes.
'
' 1740 - An event used to report that a task completed.
'
' Paramter 1: Task Name
' Paramter 2: Start Time (UTC)
' Paramter 3: Completion Time (UTC)
' Paramter 4: (Task Status not available)
'
' 1741 - An event used to report that a task is running passed the
' specified maximum task duration.
'
' Paramter 1: Task Name
' Paramter 2: Start Time (UTC)
' Paramter 3: Current Task Duration (seconds)
' Paramter 4: Maximum Task Duration (input parameter value)
'
' The following additional events can be raised:
'
' 1100 - An event used only for debugging or tracing.
' 1101 - Script executed successfully.
' 1102 - An error occurred in executing this script.
' 1105 - Accessed denied due to connection failure or permissions.
'
' Assumptions - This script will run on the SMS Site Server and access the SMS
' Site Database on the SQL Server, either locally or remotely.
' Access to the SQL Server will be using Windows Authentication so
' the user context under which the script is run must have access
' to the site database i.e. Local System.
'
' This script does not support agentless mode and will silently
' terminate. This is because of performance reasons.
'
' Parameters - MaximumTaskDuration The length of time, in seconds, for
' which all tasks should complete running.
' The default is 86400 seconds, 1 day.
'
' Change Hist - Date Version Description
' -------- --------------- -----------
' 04/20/06 05.0.2902.0000 Created
' 08/01/07 05.0.2906.0000 Changed script to run on the site
' server as opposed to the SQL Server.
' 08/18/07 6.0.5000.2 Added event tracing support.
' 09/21/07 6.0.5000.6 Changed function
' CheckWow64RegistryKeyExists() to
' not just check for the Wow6432Node
' key but also the SMS key under it.
' 01/11/08 6.0.5000.11 Added code to support site database
' on SQL Server instances.
'
' (c) Copyright 2007, Microsoft Corp., All Rights Reserved
'*******************************************************************************

Option Explicit


'Event Severity Constants
'========================

Const EVENT_TYPE_SUCCESS = 0
Const EVENT_TYPE_ERROR = 1
Const EVENT_TYPE_WARNING = 2
Const EVENT_TYPE_INFORMATION = 4

Const EVENTLOG_AUDIT_SUCCESS = 8
Const EVENTLOG_AUDIT_FAILURE = 16


'Event Number Constants
'======================

Const EVENT_ID_NOTANEVENT = 1100
Const EVENT_ID_SCRIPTSUCCESS = 1101
Const EVENT_ID_SCRIPTERROR = 1102
Const EVENT_ID_ACCESSDENIED = 1105

Const EVENT_ID_TASK_COMPLETED = 1740
Const EVENT_ID_TASK_RUNNING_TOO_LONG = 1741
Const EVENT_ID_TASK_DISABLED = 1742
Const EVENT_ID_TASK_DID_NOT_START = 1743


'Debug level constants
'=====================

Const DBG_TRACE = 1
Const DBG_WARNING = 2
Const DBG_ERROR = 3
Const DBG_NONE = 4


'Error constants
'===============

Const ERROR_INVALID_DATA = &amp;H8007000D
Const ERROR_INVALID_PARAMETER = &amp;H80070057
Const ERROR_DATABASE_DOES_NOT_EXIST = &amp;H80070429
Const ERR_BAD_CONFIGURATION = &amp;H8007064A
Const ERROR_INVALID_TABLE = &amp;H8007065C
Const ERROR_DATABASE_FAILURE = &amp;H800710D9


'Input Parameter Constants
'=========================

Const SCRIPT_PARAM_MAXIMUM_TASK_DURATION = "MaximumTaskDuration"


'Varset Constants
'================

Const VARSET_VAR_TASK_START_TIME = "Task Start Time"
Const VARSET_VAR_TASK_COMPLETION_TIME = "Task Completion Time"
Const VARSET_VAR_TASK_ENABLED = "Task Enabled"


'Task database access constants
'==============================

Const SQL_QUERY_SMS_TASKS = "select * from SQLTaskStatus"

Const SQL_RESULT_SMS_TASK_NAME = "TaskName"
Const SQL_RESULT_SMS_TASK_START_TIME = "LastStartTime"
Const SQL_RESULT_SMS_TASK_COMPLETION_TIME = "LastCompletionTime"
Const SQL_RESULT_SMS_TASK_NEXT_START_TIME = ""
Const SQL_RESULT_SMS_TASK_ENABLED = ""
Const SQL_RESULT_SMS_TASK_STATUS = "CompletionStatus"


'Other constants
'===============

Const TASK_NAME = "Site Maintenance"


' Global variables
'=================

Dim g_oUtil ' Utility class for MOM events, logging and registry access.
Dim g_oDictionary ' Stores varset data. Note, only string data can be stored.



Sub Main()

Dim bEventTracing

Dim strError

Dim intMaximumTaskDuration


On Error Resume Next


LogMessage DBG_TRACE, ScriptContext.Name &amp; " script starting at local time: " &amp; CStr(Time)

'Check if event tracing is configured. If it is, raise a start event.
'=====================================================================

bEventTracing = IsEventTracingEnabled()

If (bEventTracing = True) Then
LogEvent EVENT_ID_NOTANEVENT, EVENT_TYPE_INFORMATION, "started at local time: " &amp; CStr(Time)
End If

'This script does not support agentless monitoring.
'==================================================

If ScriptContext.IsTargetAgentless Then
LogMessage DBG_TRACE, "No action taken; agentless monitoring is not supported."
LogMessage DBG_TRACE, ScriptContext.Name &amp; " script completed at local time: " &amp; CStr(Time)
Exit Sub
End If

'Initialize utility object and set tracing leve for it.
'======================================================

Set g_oUtil = new Util

If IsEmpty(g_oUtil) Then
LogMessage DBG_TRACE, "Failed to instantiate Util object."
ScriptError "instantiate Util object."
LogMessage DBG_TRACE, ScriptContext.Name &amp; " script completed at local time: " &amp; CStr(Time)
Exit Sub
End If

g_oUtil.SetDebugLevel(g_oUtil.DBG_NONE)

'Get input parameters.
'=====================

intMaximumTaskDuration = CLng(ScriptContext.Parameters.Get(SCRIPT_PARAM_MAXIMUM_TASK_DURATION))

If ((0 &lt;&gt; Err.number) or _
IsEmpty(intMaximumTaskDuration) or _
(intMaximumTaskDuration &lt;= 0)) Then
LogMessage DBG_ERROR, "Failed to get script parameter " &amp; SCRIPT_PARAM_MAXIMUM_TASK_DURATION &amp; " or invalid value."
ScriptError "get script parameter " &amp; SCRIPT_PARAM_MAXIMUM_TASK_DURATION &amp; " or invalid value."
Set g_oUtil = Nothing
Exit Sub
End If

'Check tasks found in the SMS Site Database.
'===========================================

CheckTasksInSiteDatabase intMaximumTaskDuration

If 0 &lt;&gt; Err.number Then
strError = GetErrorString(Err)
LogMessage DBG_ERROR, "Failed to check tasks in SMS site database." &amp; strError
ScriptError "check tasks in SMS site database." &amp; strError
End If

Set g_oUtil = Nothing

If (bEventTracing = True) Then
LogEvent EVENT_ID_SCRIPTSUCCESS, EVENT_TYPE_INFORMATION, "completed at local time: " &amp; CStr(Time)
End If

LogMessage DBG_TRACE, ScriptContext.Name &amp; " script completed at local time: " &amp; CStr(Time)

End Sub


'******************************************************************************
' Name: CheckTasksInSiteDatabase
'
' Purpose: Checks all tasks found in the SMS site database.
'
' Parameters: intMaximumTaskDuration The length of time, in seconds, in
' which a task should complete.
'
' Returns: Nothing
'
Sub CheckTasksInSiteDatabase(intMaximumTaskDuration)

Dim strDBName
Dim strSQLServer
Dim strSQLServerInstance
Dim strSiteCode


On Error Resume Next


LogMessage DBG_TRACE, "Checking tasks."

'Check input parameters.
'=======================

If (IsEmpty(intMaximumTaskDuration) Or (intMaximumTaskDuration &lt;= 0)) Then
LogMessage DBG_ERROR, "Invalid input parameter."
Err.Raise ERROR_INVALID_PARAMETER
Exit Sub
End If

'Get the name of the SQL server, SQL Server Instance and the Site
'Database.
'================================================================

strSQLServer = GetSQLServerName()

If IsEmpty(strSQLServer) Or (strSQLServer = "") Then
LogMessage DBG_ERROR, "Failed to get SQL Server name."
Err.Raise ERR_BAD_CONFIGURATION
Exit Sub
End If

GetSQLServerInstanceNameAndDatabaseName strSQLServerInstance, strDBName

If Err Then
Exit Sub
End If

'Get the Site Code for this SMS Site Server and site.
'====================================================

strSiteCode = GetSiteCode()

If IsEmpty(strSiteCode) Or (strSiteCode = "") Then
LogMessage DBG_ERROR, "Failed to get site code."
Err.Raise ERR_BAD_CONFIGURATION
Exit Sub
End If

'Check tasks in the site database.
'=================================

CheckTasks strSQLServer, strSQLServerInstance, strDBName, strSiteCode, intMaximumTaskDuration

End Sub


'******************************************************************************
' Name: GetSQLServerName
'
' Purpose: Gets the name of the SQL Server hosting the SMS Site Database.
'
' Parameters: None
'
' Returns: Registry key string value SOFTWARE\Microsoft\SMS\SQL Server\
' Server
'
Function GetSQLServerName()

GetSQLServerName = g_oUtil.ReadRegistryStringValue(g_oUtil.HKEY_LOCAL_MACHINE, g_oUtil.REG_KEY_SMS_SERVER_SQL_SERVER, g_oUtil.REG_VALUE_SMS_SERVER_SERVER)

End Function


'******************************************************************************
' Name: GetSQLServerInstanceNameAndSiteDatabaseName
'
' Purpose: Gets the name of the SQL Server Instance hosting the SMS Site
' Database as well as the name of the database.
'
' Parameters: strSQLServerInstanceName Instance on the SQL Server hosting the
' site database. If empty, the database
' is on the default instance.
' strSiteDatabaseName The name of the site database.
'
' Returns: Nothing
'
Sub GetSQLServerInstanceNameAndDatabaseName(strSQLServerInstanceName, strSiteDatabaseName)

Dim strDBName
Dim strSQLServer
Dim strSiteCode

Dim intBackSlashCharPos


On Error Resume Next


LogMessage DBG_TRACE, "Getting SQL Server Instance Name and Site Database Name."

'Get from the registry the value of Database Name.
'=================================================

strDBName = GetSiteDatabaseName()

If IsEmpty(strDBName) Or (strDBName = "") Then
LogMessage DBG_ERROR, "Failed to get SQL Server instance and site database name."
Err.Raise ERR_BAD_CONFIGURATION
Exit Sub
End If

'Parse the Database Name to get the SQL Server Instance Name and Site
'Database Name. This is done because the Database Name value was
'overloaded with the SQL Server Instance Name.
'====================================================================

intBackSlashCharPos = InStr(1, strDBName, "\")

If IsNull(intBackSlashCharPos) Or (intBackSlashCharPos = 0) Then

If Not IsEmpty(strSQLServerInstanceName) Then
strSQLServerInstanceName.Empty()
End If

strSiteDatabaseName = strDBName
Else
strSQLServerInstanceName = Left(strDBName, intBackSlashCharPos - 1)
strSiteDatabaseName = Right(strDBName, Len(strDBName) - intBackSlashCharPos)
End If

End Sub


'******************************************************************************
' Name: GetSiteDatabaseName
'
' Purpose: Gets the name of the SMS Site Database.
'
' Parameters: None
'
' Returns: Registry key string value SOFTWARE\Microsoft\SMS\SQL Server\
' Database Name
'
Function GetSiteDatabaseName()

GetSiteDatabaseName = g_oUtil.ReadRegistryStringValue(g_oUtil.HKEY_LOCAL_MACHINE, g_oUtil.REG_KEY_SMS_SERVER_SQL_SERVER, g_oUtil.REG_VALUE_SMS_SERVER_DATABASE_NAME)

End Function


'******************************************************************************
' Name: GetSiteCode
'
' Purpose: Gets the SMS Site Code.
'
' Parameters: None
'
' Returns: Registry key string value SOFTWARE\Microsoft\SMS\Identification\
' Site Code
'
Function GetSiteCode()

GetSiteCode = g_oUtil.ReadRegistryStringValue(g_oUtil.HKEY_LOCAL_MACHINE, g_oUtil.REG_KEY_SMS_SERVER_IDENTIFICATION, g_oUtil.REG_VALUE_SMS_SERVER_SITE_CODE)

End Function


'******************************************************************************
' Name: CheckTasks
'
' Purpose: Check tasks found in the specified SMS Site Database. The
' specified database should be an active database for an SMS site.
'
' Parameters: strComputer Fully qualified computer name for the
' SQL server.
' strSQLServerInstance Instance on the SQL Server hosting the
' site database. If empty, the database
' is on the default instance.
' strDBName Name of the SMS Site Database to query.
' strSiteCode SMS Site Code for the database.
' intMaximumTaskDuration The length of time, in seconds, in
' which a task should complete.
'
' Returns: Nothing
'
Sub CheckTasks(strComputer, strSQLServerInstance, strDBName, strSiteCode, intMaximumTaskDuration)

Dim cnADOConnection
Dim rsTask

Dim intRecordCount

Dim strError
Dim strParam
Dim strQuery

Dim dtDateTimeStamp


On Error Resume Next


'Check input parameters.
'=======================

If (IsEmpty(strComputer) Or _
IsEmpty(strDBName) Or _
IsEmpty(strSiteCode) Or _
(IsEmpty(intMaximumTaskDuration) Or (intMaximumTaskDuration &lt;= 0))) Then
LogMessage DBG_ERROR, "Invalid input parameter."
Err.Raise ERROR_INVALID_PARAMETER
Exit Sub
End If

If IsEmpty(strSQLServerInstance) Then
LogMessage DBG_TRACE, "Checking tasks in site database '" &amp; strDBName &amp; _
"' on SQL Server '" &amp; strComputer &amp; _
"' for site '" &amp; strSiteCode &amp; "'."
Else
LogMessage DBG_TRACE, "Checking tasks in site database '" &amp; strDBName &amp; _
"' on SQL Server '" &amp; strComputer &amp; _
"', instance '" &amp; strSQLServerInstance &amp; _
"', for site '" &amp; strSiteCode &amp; "'."
End If

LogMessage DBG_TRACE, "Using a maximum task duration of '" &amp; intMaximumTaskDuration &amp; "'."

'Open a connection to the SMS site database in the default SQL
'instance using the OLE DB provider.
'=============================================================

Set cnADOConnection = CreateObject("ADODB.Connection")

cnADOConnection.Provider = "sqloledb"
cnADOConnection.ConnectionTimeout = 900 '15 minutes
cnADOConnection.CommandTimeout = 900 '15 minutes

If IsEmpty(strSQLServerInstance) Then
strParam = "Server=" &amp; strComputer &amp; ";Database=" &amp; strDBName &amp; ";Trusted_Connection=yes"
Else
strParam = "Server=" &amp; strComputer &amp; "\" &amp; strSQLServerInstance &amp; ";Database=" &amp; strDBName &amp; ";Trusted_Connection=yes"
End If

cnADOConnection.Open strParam

If Err Then
strError = GetErrorString(Err)
If IsEmpty(strSQLServerInstance) Then
LogMessage DBG_ERROR, "Failed to connect to the SMS Site Database '" &amp; strDBName &amp; "' on SQL Server '" &amp; strComputer &amp; "'." &amp; strError
ScriptError "connect to the SMS Site Database '" &amp; strDBName &amp; "' on SQL Server '" &amp; strComputer &amp; "'." &amp; strError
Else
LogMessage DBG_ERROR, "Failed to connect to the SMS Site Database '" &amp; strDBName &amp; "' on SQL Server '" &amp; strComputer &amp; "', instance '" &amp; strSQLServerInstance &amp; "'." &amp; strError
ScriptError "connect to the SMS Site Database '" &amp; strDBName &amp; "' on SQL Server '" &amp; strComputer &amp; "', instance '" &amp; strSQLServerInstance &amp; "'." &amp; strError
End If
Set cnADOConnection = Nothing
Exit Sub
End If

'Query existing tasks.
'=====================

strQuery = SQL_QUERY_SMS_TASKS
LogMessage DBG_TRACE, "SQL query: " &amp; strQuery

LogMessage DBG_TRACE, "Executing query at local time: " &amp; CStr(Time)
Set rsTask = cnADOConnection.Execute(strQuery)
LogMessage DBG_TRACE, "Query completed at local time: " &amp; CStr(Time)

If Err Then
LogMessage DBG_ERROR, "Failed to execute query."
cnADOConnection.Close
Set cnADOConnection = Nothing
Exit Sub
End If

'Get the current UTC date and time as the time stamp for the returned
'record set.
'====================================================================

'dtDateTimeStamp = GetCurrentDateTimeUTC() 'old way of calculating current UTC time

Dim rsUtcDate
rsUtcDate = cnADOConnection.Execute("SELECT GETUTCDATE() AS 'SQL UTC Date'")
dtDateTimeStamp = rsUtcDate("SQL UTC Date").Value

'Check each returned task. If an error is returned, stop checking the
'remaining tasks since they will most likely have the same problem and
'this will prevent a flood of script error events.
'=====================================================================

intRecordCount = 0

Do While (Not rsTask.EOF)

CheckTask strSiteCode, rsTask, dtDateTimeStamp, intMaximumTaskDuration

If Err Then
Exit Do
End If

intRecordCount = intRecordCount + 1

rsTask.MoveNext

Loop

LogMessage DBG_TRACE, "The total number of successfully checked tasks was '" &amp; intRecordCount &amp; "'."

'Close the connection to the SMS site database.
'==============================================

cnADOConnection.Close

Set cnADOConnection = Nothing
Set rsTask = Nothing

End Sub


'******************************************************************************
' Name: CheckTask
'
' Purpose: Checks the specified task and raises the appropriate MOM events.
'
' Parameters: strSiteCode SMS Site Code for the SMS task.
' rsTask ADO RecordSet object for an SMS task.
' dtDateTimeStamp Time stamp (UTC) for the record set.
' intMaximumTaskDuration The length of time, in seconds, in
' which a task should complete.
'
' Returns: Nothing
'
Sub CheckTask(strSiteCode, rsTask, dtDateTimeStamp, intMaximumTaskDuration)

Dim strError
Dim strTaskName
Dim strStartDateTime
Dim strCompletionDateTime
Dim strPreviousStartDateTime
Dim strPreviousCompletionDateTime

Dim dtStartDateTime
Dim dtCompletionDateTime

Dim intError
Dim intTaskStatus
Dim intDateDiffSeconds


On Error Resume Next


'Check input parameters.
'=======================

If (IsEmpty(strSiteCode) Or _
IsEmpty(rsTask) Or _
IsEmpty(dtDateTimeStamp) Or _
(IsEmpty(intMaximumTaskDuration) Or (intMaximumTaskDuration &lt;= 0))) Then
LogMessage DBG_ERROR, "Invalid input parameter."
Err.Raise ERROR_INVALID_PARAMETER
Exit Sub
End If

'Get task data from the record. All times are in local time and
'therefore must be converted to UTC.
'===============================================================

strTaskName = rsTask(SQL_RESULT_SMS_TASK_NAME).Value
dtStartDateTime = rsTask(SQL_RESULT_SMS_TASK_START_TIME).Value
dtCompletionDateTime = rsTask(SQL_RESULT_SMS_TASK_COMPLETION_TIME).Value
intTaskStatus = rsTask(SQL_RESULT_SMS_TASK_STATUS).Value

If Err Then
intError = Err.number
strError = GetErrorString(Err)
LogMessage DBG_ERROR, "Failed to get record value for SMS task '" &amp; strTaskName &amp; "'." &amp; strError
ScriptError "get record value for SMS task '" &amp; strTaskName &amp; "'." &amp; strError
Err.Raise intError
Exit Sub
End If

dtStartDateTime = ConvertLocalDateTimeToUTC(dtStartDateTime)
dtCompletionDateTime = ConvertLocalDateTimeToUTC(dtCompletionDateTime)

strStartDateTime = CStr(dtStartDateTime)
strCompletionDateTime = CStr(dtCompletionDateTime)

'Get previously saved data for this task. All times are in UTC.
'===============================================================

strPreviousStartDateTime = GetPreviousTaskData(VARSET_VAR_TASK_START_TIME, strTaskName)
strPreviousCompletionDateTime = GetPreviousTaskData(VARSET_VAR_TASK_COMPLETION_TIME, strTaskName)

'Check if the task is still running or has completed.
'====================================================

If (strCompletionDateTime = strPreviousCompletionDateTime) Then

'If the task has not started since the last time that it was
'polled nothing has changed. If the task has started, check if
'it has exceeded the configured maximum task duration. If the
'duration has been exceeded, create an event to report it.
'==============================================================

If (strStartDateTime &lt;&gt; strPreviousStartDateTime) Then

intDateDiffSeconds = DateDiff("s", dtStartDateTime, dtDateTimeStamp)

If intDateDiffSeconds &gt; intMaximumTaskDuration Then
CreateTaskRunningTooLongEvent strSiteCode, strTaskName, dtStartDateTime, intDateDiffSeconds, intMaximumTaskDuration
End If

If intDateDiffSeconds &lt; -1 Then
LogMessage DBG_ERROR, "Failed to calculate current runing time for SMS task '" &amp; strTaskName &amp; "'."
ScriptError "calculate current runing time for SMS task '" &amp; strTaskName &amp; "'."
Err.Raise ERROR_INVALID_DATA
Exit Sub
End If

End If

Else

'The task has completed. Save its current start and completion
'times. If this is not the first time that the script has run,
'create an event to report its completion task data. Performing
'this check will prevent sending duplicate events in the case that
'the MOM service is bounced but it could also result in some task
'executions being missed depending on the run interval for this
'script.
'=================================================================

SetPreviousTaskData VARSET_VAR_TASK_START_TIME, strTaskName, strStartDateTime
SetPreviousTaskData VARSET_VAR_TASK_COMPLETION_TIME, strTaskName, strCompletionDateTime

If Not IsEmpty(strPreviousCompletionDateTime) Then
CreateTaskCompletedEvent strSiteCode, strTaskName, dtStartDateTime, dtCompletionDateTime, intTaskStatus
End If

End If

End Sub


'******************************************************************************
' Name: CreateTaskRunningTooLongEvent
'
' Purpose: To generate a MOM event to report that a task has run longer than
' its configured maximum task duration.
'
' Parameters: strSiteCode SMS Site Code for the SMS task.
' strTaskName Name of the currently running SMS task.
' dtStartTime The time (UTC) that the task started.
' intCurrentTaskDuration The length of time, in seconds, that
' the task has been running.
' intMaximumTaskDuration The length of time, in seconds, in
' which a task should complete.
'
Sub CreateTaskRunningTooLongEvent(strSiteCode, strTaskName, dtStartTime, intCurrentTaskDuration, intMaximumTaskDuration)

Dim oEvent

Dim strMessage

On Error Resume Next

If IsNull(dtStartTime) Then dtStartTime = "NULL"

'Create MOM event object.
'========================

Set oEvent = ScriptContext.CreateEvent

'Initialize the event object.
'============================

oEvent.EventType = EVENT_TYPE_WARNING
oEvent.EventNumber = EVENT_ID_TASK_RUNNING_TOO_LONG
oEvent.Category = strSiteCode

oEvent.SetEventParameter(strTaskName) ' Parameter1
oEvent.SetEventParameter(dtStartTime) ' Parameter2
oEvent.SetEventParameter(intCurrentTaskDuration) ' Parameter3
oEvent.SetEventParameter(intMaximumTaskDuration) ' Parameter4
oEvent.SetEventParameter(TASK_NAME) ' Parameter5

strMessage = "%5 task '%1' is still running. The task started at '%2' and was expected to complete within '%4' seconds. It has now run for '%3' seconds."

oEvent.Message = strMessage

LogMessage DBG_TRACE, strMessage
LogMessage DBG_TRACE, "Submitting event " &amp; EVENT_ID_TASK_RUNNING_TOO_LONG &amp; "."

'Submit, raise, this event to MOM.
'=================================

ScriptContext.Submit oEvent

'Cleanup
'=======

Set oEvent = Nothing

End Sub


'******************************************************************************
' Name: CreateTaskCompletedEvent
'
' Purpose: To generate a MOM event to report that a task has run longer than
' its configured maximum task duration.
'
' Parameters: strSiteCode SMS Site Code for the SMS task.
' strTaskName Name of the currently running SMS task.
' dtStartTime The time (UTC) that the task started.
' dtCompletionTime The time (UTC) that the task completed.
' intTaskStatus If not empty, the execution status for
' the task.
'
Sub CreateTaskCompletedEvent(strSiteCode, strTaskName, dtStartTime, dtCompletionTime, intTaskStatus)

Dim oEvent

Dim strMessage


On Error Resume Next

If IsNull(dtStartTime) Then dtStartTime = "NULL"

'Create MOM event object.
'========================

Set oEvent = ScriptContext.CreateEvent

'Initialize the event object.
'============================

oEvent.EventType = EVENT_TYPE_INFORMATION
oEvent.EventNumber = EVENT_ID_TASK_COMPLETED
oEvent.Category = strSiteCode

oEvent.SetEventParameter(strTaskName) ' Parameter1
oEvent.SetEventParameter(dtStartTime) ' Parameter2
oEvent.SetEventParameter(dtCompletionTime) ' Parameter3

strMessage = TASK_NAME &amp; " task '%1' has completed. The task started at '%2' and completed at '%3'."

If Not IsEmpty(intTaskStatus) Then
oEvent.SetEventParameter(intTaskStatus) ' Parameter4
strMessage = strMessage &amp; " Task status is '%4'."
End If

oEvent.Message = strMessage

LogMessage DBG_TRACE, strMessage
LogMessage DBG_TRACE, "Submitting event " &amp; EVENT_ID_TASK_COMPLETED &amp; "."

'Submit, raise, this event to MOM.
'=================================

ScriptContext.Submit oEvent

'Cleanup
'=======

Set oEvent = Nothing

End Sub


'******************************************************************************
' Name: GetCurrentDateTimeUTC
'
' Purpose: Gets the current date and time in UTC format.
'
' Parameters: None
'
' Returns: Date, current date and time
'
Function GetCurrentDateTimeUTC()

Dim oTimeZone
Dim oTimeZoneSet
Dim CurrentDateTimeLocal
Dim intBias


On Error Resume Next


'Get the instances of this computer's time zone under the WMI CIMV2
'namespace. There will be only one for the current system. Convert
'the current local time to UTC time; UTC = local time + bias. The
'bias is obtained from the Win32_TimeZone class.
'===================================================================

Set oTimeZoneSet = GetObject("winmgmts:").InstancesOf("Win32_TimeZone")

If Err Then
Err.Clear
Exit Function
End If

If Not IsEmpty(oTimeZoneSet) Then

For Each oTimeZone In oTimeZoneSet

'Convert the current local time to UTC time.
'
'A negative time zone bias indicates that the local time is
'earlier than GMT time, a UTC time with zero bias or offset.
'A negative time zone bias must therefore be added to the
'local time. Likewise, a positive one subtracted. The
'daylight savings bias can be added directly though. Thus
'
'Bias = -TimeZoneBias + DaylightSavingsBias
'UTC = LocalTime + Bias. Bias is in minutes.
'===========================================================

CurrentDateTimeLocal = Now

intBias = -oTimeZone.Bias

If Not IsEmpty(oTimeZone.DaylightDay) Then
intBias = intBias + oTimeZone.DaylightBias
End If

GetCurrentDateTimeUTC = DateAdd("n", intBias, CurrentDateTimeLocal) 'In minutes

Next

Set oTimeZoneSet = Nothing

End If

Err.Clear

End Function


'******************************************************************************
' Name: ConvertLocalDateTimeToUTC
'
' Purpose: Converts the specified local date and time to UTC format.
'
' Parameters: dtLocal
'
' Returns: UTC date and time
'
Function ConvertLocalDateTimeToUTC(dtLocal)

Dim oTimeZone
Dim oTimeZoneSet
Dim intBias


On Error Resume Next


'Get the instances of this computer's time zone under the WMI CIMV2
'namespace. There will be only one for the current system. Convert
'the specified local time to UTC time; UTC = local time + bias. The
'bias is obtained from the Win32_TimeZone class.
'===================================================================

Set oTimeZoneSet = GetObject("winmgmts:").InstancesOf("Win32_TimeZone")

If Err Then
Err.Clear
Exit Function
End If

If Not IsEmpty(oTimeZoneSet) Then

For Each oTimeZone In oTimeZoneSet

'Convert the specified local time to UTC time.
'
'A negative time zone bias indicates that the local time is
'earlier than GMT time, a UTC time with zero bias or offset.
'A negative time zone bias must therefore be added to the
'local time. Likewise, a positive one subtracted. The
'daylight savings bias can be added directly though. Thus
'
'Bias = -TimeZoneBias + DaylightSavingsBias
'UTC = LocalTime + Bias. Bias is in minutes.
'===========================================================

intBias = -oTimeZone.Bias

If Not IsEmpty(oTimeZone.DaylightDay) Then
intBias = intBias + oTimeZone.DaylightBias
End If

ConvertLocalDateTimeToUTC = DateAdd("n", intBias, dtLocal) 'In minutes

Next

Set oTimeZoneSet = Nothing

End If

Err.Clear

End Function


'******************************************************************************
' Name: GetErrorString
'
' Purpose: Attempts to find the description for an error if an error with
' no description is passed in.
'
' Parameters: oErr The error object
'
' Returns: String, the description for the error. (Includes the error code.)
'
Function GetErrorString(oErr)

Dim lErr
Dim strErr


lErr = oErr
strErr = oErr.Description

On Error Resume Next


If 0 &gt;= Len(strErr) Then

'If we don't have an error description, then check to see if the
'error is a 0x8007xxxx error. If it is, then look it up.
'===============================================================

Const ErrorMask = &amp;HFFFF0000
Const HiWord8007 = &amp;H80070000
Const LoWordMask = 65535 ' This is equivalent to 0x0000FFFF

If (lErr And ErrorMask) = HiWord8007 Then

'Attempt to use 'net helpmsg' to get a description for the error.
'================================================================

Dim oShell
Set oShell = CreateObject("WScript.Shell")

If Err = 0 Then

Dim oExec
Set oExec = oShell.Exec("net helpmsg " &amp; (lErr And LoWordMask))

Dim strMessage, i
Do
strMessage = oExec.stdout.ReadLine()
i = i + 1
Loop While (Len(strMessage) = 0) And (i &lt; 5)

strErr = strMessage

End If

End If

End If

GetErrorString = vbCrLf &amp; "The error returned was: '" &amp; strErr &amp; "' " &amp; lErr &amp; " (0x" &amp; Hex(lErr) &amp; ")"

End Function


'******************************************************************************
' Name: ScriptError
'
' Purpose: To generate a warning about a runtime script error.
'
' Parameters: strError The description of the error
'
' Returns: Nothing
'
Sub ScriptError(strError)

LogEvent EVENT_ID_SCRIPTERROR, EVENT_TYPE_WARNING, "encountered a runtime error." &amp; vbCrLf &amp; "Failed to " &amp; strError

End Sub


'******************************************************************************
' Name: LogEvent
'
' Purpose: To generate a MOM event
'
' Parameters: lEventID The event code
' lEventType The severity of the event
' strMessage The message to include in the event
'
' Returns: Nothing
'
Sub LogEvent(lEventID, lEventType, strMessage)

Dim oEvent


On Error Resume Next

Set oEvent = ScriptContext.CreateEvent

oEvent.EventNumber = lEventID
oEvent.EventType = lEventType
oEvent.SetEventParameter(ScriptContext.Name) 'Parameter 1
oEvent.SetEventParameter(ScriptContext.ProcessingRule.Name) 'Parameter 2
oEvent.SetEventParameter(strMessage) 'Parameter3

oEvent.Message = "The script '%1' running under processing rule '%2' %3"

ScriptContext.Submit oEvent

End Sub


'******************************************************************************
' Name: LogMessage
'
' Purpose: To log a message to ScriptContext and MOM's agent response log.
'
' Parameters: lLevel The debug level for this message i.e. trace,
' warning or error
' strMessage The message to write
'
' Returns: Nothing
'
Sub LogMessage(lLevel, strMessage)

If (lLevel &lt; DBG_NONE) Then

If (lLevel = DBG_ERROR) Then
ScriptContext.Echo "[Error]: " + strMessage
ElseIf (lLevel = DBG_WARNING) Then
ScriptContext.Echo "[Warning]: " + strMessage
ElseIf (lLevel = DBG_TRACE) Then
ScriptContext.Echo "[Trace]:" + strMessage
End If

End If

End Sub


'******************************************************************************
' Name: GetPreviousTaskData
'
' Purpose: Retrieves previously saved task data out of a varset.
'
' Parameters: strVariableName, the variable name for the data.
' strTaskName, the task associated with the variable
'
' Returns: String, the data to return or zero
'
Function GetPreviousTaskData(strVariableName, strTaskName)

Dim strVarsetName

Dim objScriptState
Dim objVarSet


On Error Resume Next


strVarsetName = ScriptContext.Name &amp; " " &amp; strVariableName

Set objScriptState = ScriptContext.GetScriptState()
Set objVarSet = objScriptState.GetSet(strVarsetName)

GetPreviousTaskData = objVarSet.get(strTaskName)
'LogEvent EVENT_ID_NOTANEVENT, EVENT_TYPE_INFORMATION, "found previous " &amp; strVariableName &amp; " for task " &amp; strTaskName &amp; " = " &amp; GetPreviousTaskData

Set objVarSet = Nothing
Set objScriptState = Nothing

End Function


'******************************************************************************
' Name: SetPreviousTaskData
'
' Purpose: Saves the specified task data value in a varset. If the key
' exists then the data associated with that key is replaced,
' otherwise the key/data combination is added to the varset.
'
' Parameters: strVariableName, the variable name for the data.
' strTaskName, the task associated with the variable
' strData, the data value for the task.
'
' Returns: Nothing
'
Sub SetPreviousTaskData(strVariableName, strTaskName, strData)

Dim strVarsetName

Dim objScriptState
Dim objVarSet


On Error Resume Next


'Get the varset for the specified task variable. If it does not
'exist, create it.
'===============================================================

strVarsetName = ScriptContext.Name &amp; " " &amp; strVariableName

Set objScriptState = ScriptContext.GetScriptState()
Set objVarSet = objScriptState.GetSet(strVarsetName)

If IsEmpty(objVarSet) Then
objVarSet = objScriptState.CreateSet()
End If

'Set, the data value.
'====================

objVarSet.put strTaskName, strData

objScriptState.SaveSet strVarsetName, objVarSet

Set objVarSet = Nothing
Set objScriptState = Nothing

End Sub


'==========================================================================
' Class: Util
' Description: Wrapper around WMI.
'==========================================================================
Class Util

'---------------
' Constants (Initialized on constructor due to VBS behavior)
'---------------

'Used to indicate to LogMessage when/how to print the message.
Public DBG_NONE
Public DBG_ERROR
Public DBG_WARNING
Public DBG_TRACE

'Internal Debug Level
Private m_nDebugLevel

'Registry hive constants
Public HKEY_CLASSES_ROOT
Public HKEY_CURRENT_USER
Public HKEY_LOCAL_MACHINE
Public HKEY_USERS
Public HKEY_CURRENT_CONFIG
Public HKEY_DYN_CONFIG

'Registry access permissions
Public KEY_QUERY_VALUE
Public KEY_SET_VALUE
Public KEY_CREATE_SUB_KEY
Public KEY_ENUMERATE_SUB_KEYS
Public KEY_NOTIFY
Public KEY_CREATE_LINK
Public DELETE
Public READ_CONTROL
Public WRITE_DAC
Public WRITE_OWNER

'Registry path and key name constants
Public REG_PATH_SERVICES
Public REG_PATH_SERVICES_BASE

Public REG_PATH_SMS
Public REG_PATH_SMS_BASE

Public REG_PATH_SMS_SERVER

Public REG_PATH_SMS_SERVER_OPMGMT_SMS_SERVER_ROLE
Public REG_PATH_SMS_SERVER_OPMGMT_SMS_SERVER_ROLE_BASE

Public REG_KEY_SMS_SERVER_IDENTIFICATION
Public REG_KEY_SMS_SERVER_OPERATIONS_MANAGEMENT
Public REG_KEY_SMS_SERVER_SETUP
Public REG_KEY_SMS_SERVER_SQL_SERVER

Public REG_KEY_SMS_SERVER_OPMGMT_SQL_SERVER

'Registry key value name constants
Public REG_VALUE_SERVICES_DISPLAY_NAME

Public REG_VALUE_SMS_SERVER_VERSION
Public REG_VALUE_SMS_SERVER_FULL_VERSION
Public REG_VALUE_SMS_SERVER_SITE_CODE
Public REG_VALUE_SMS_SERVER_PARENT_SITE_CODE
Public REG_VALUE_SMS_SERVER_CENTRAL_SITE
Public REG_VALUE_SMS_SERVER_BINARY_DIRECTORY
Public REG_VALUE_SMS_SERVER_TYPE
Public REG_VALUE_SMS_SERVER_DATABASE_NAME
Public REG_VALUE_SMS_SERVER_SERVER

'---------------
' Methods
'---------------

'=============
' Method: Class_Initialize
' Description: This is the constructor
' Parameters:
'=============
Private Sub Class_Initialize()

'Initialize Debug level constants
DBG_TRACE = 1
DBG_WARNING = 2
DBG_ERROR = 3
DBG_NONE = 4

'by default only errors are logged
m_nDebugLevel = DBG_ERROR

'Registry hive constants
HKEY_CLASSES_ROOT = &amp;H80000000
HKEY_CURRENT_USER = &amp;H80000001
HKEY_LOCAL_MACHINE = &amp;H80000002
HKEY_USERS = &amp;H80000003
HKEY_CURRENT_CONFIG = &amp;H80000005
HKEY_DYN_CONFIG = &amp;H80000006

'Registry access permissions
KEY_QUERY_VALUE = &amp;H1
KEY_SET_VALUE = &amp;H2
KEY_CREATE_SUB_KEY = &amp;H4
KEY_ENUMERATE_SUB_KEYS = &amp;H8
KEY_NOTIFY = &amp;H10
KEY_CREATE_LINK = &amp;H20
DELETE = &amp;H10000
READ_CONTROL = &amp;H20000
WRITE_DAC = &amp;H40000
WRITE_OWNER = &amp;H80000

'Registry path and key name constants
REG_PATH_SERVICES = "SYSTEM\CurrentControlSet\Services"
REG_PATH_SERVICES_BASE = REG_PATH_SERVICES + "\"

'Removing use of unreliable CheckWow64RegistryKeyExists function
'If (CheckWow64RegistryKeyExists() = True) Then
' REG_PATH_SMS = "SOFTWARE\Wow6432Node\Microsoft\SMS"
'Else
' REG_PATH_SMS = "SOFTWARE\Microsoft\SMS"
'End If

'Adding this instead
On Error Resume Next
Dim sCimv2namespace, sProcArchQuery, oProcArchObjectSet, oProcArchObject, sProcArch
sCimv2namespace = "winmgmts:\\.\root\cimv2"
sProcArchQuery = "Select * From Win32_Environment Where Name = ""Processor_Architecture"""
Set oProcArchObjectSet = WMIExecQuery (sCimv2namespace, sProcArchQuery)
Set oProcArchObject = oProcArchObjectSet.Item("Win32_Environment.Name=""PROCESSOR_ARCHITECTURE"",UserName=""&lt;SYSTEM&gt;""")
sProcArch = oProcArchObject.VariableValue
On Error GoTo 0
Select Case sProcArch
Case "AMD64"
REG_PATH_SMS = "SOFTWARE\Wow6432Node\Microsoft\SMS"
Case "x86"
REG_PATH_SMS = "SOFTWARE\Microsoft\SMS"
Case Else
ScriptError "read %PROCESSOR_ARCHITECTURE environment variable from Win32_Environment WMI class."
End Select

REG_PATH_SMS_BASE = REG_PATH_SMS + "\"

REG_PATH_SMS_SERVER = REG_PATH_SMS

REG_PATH_SMS_SERVER_OPMGMT_SMS_SERVER_ROLE = REG_PATH_SMS_BASE + "Operations Management\SMS Server Role"
REG_PATH_SMS_SERVER_OPMGMT_SMS_SERVER_ROLE_BASE = REG_PATH_SMS_SERVER_OPMGMT_SMS_SERVER_ROLE + "\"

REG_KEY_SMS_SERVER_IDENTIFICATION = REG_PATH_SMS_BASE + "Identification"
REG_KEY_SMS_SERVER_OPERATIONS_MANAGEMENT = REG_PATH_SMS_BASE + "Operations Management"
REG_KEY_SMS_SERVER_SETUP = REG_PATH_SMS_BASE + "Setup"
REG_KEY_SMS_SERVER_SQL_SERVER = REG_PATH_SMS_BASE + "SQL Server"

REG_KEY_SMS_SERVER_OPMGMT_SQL_SERVER = REG_PATH_SMS_SERVER_OPMGMT_SMS_SERVER_ROLE_BASE + "SMS SQL Server"

'Registry key value name constants
REG_VALUE_SERVICES_DISPLAY_NAME = "DisplayName"

REG_VALUE_SMS_SERVER_VERSION = "Version"
REG_VALUE_SMS_SERVER_FULL_VERSION = "Full Version"
REG_VALUE_SMS_SERVER_SITE_CODE = "Site Code"
REG_VALUE_SMS_SERVER_PARENT_SITE_CODE = "Parent Site Code"
REG_VALUE_SMS_SERVER_CENTRAL_SITE = "Central Site"
REG_VALUE_SMS_SERVER_BINARY_DIRECTORY = "Binary Directory"
REG_VALUE_SMS_SERVER_TYPE = "Type"
REG_VALUE_SMS_SERVER_DATABASE_NAME = "Database Name"
REG_VALUE_SMS_SERVER_SERVER = "Server"

End Sub

'=============
' Method: Class_Terminate
' Description: This is the destructor
' Parameters:
'=============
Private Sub Class_Terminate()
End Sub

'=============
' Method: SetDebugLevel
' Description: To change the debugging output level of information
' generated by this utility.
' Parameters:
' nLevel - Level, either DBG_NONE, DBG_TRACE,
' DBG_WARNING or DBG_ERROR
'=============
Public Sub SetDebugLevel(ByVal nLevel)
m_nDebugLevel = nLevel
End Sub

'=============
' Method: LogMessage
' Description: Log a debug message to ScriptContext
' Parameters:
' nLevel - Debug level for the message that we're logging.
' strMessage - The message to write to the trace.
'=============
Public Sub LogMessage(ByVal nLevel, ByVal strMessage)

If (nLevel &lt;= m_nDebugLevel) Then
If (nLevel = DBG_ERROR) Then
ScriptContext.Echo "[Error]: " + strMessage
ElseIf (nLevel = DBG_WARNING) Then
ScriptContext.Echo "[Warning]: " + strMessage
ElseIf (nLevel = DBG_TRACE) Then
ScriptContext.Echo "[Trace]:" + strMessage
End If
End If

End Sub

'=============
' Method: ReadRegistryStringValue
' Description: Used to read strings from the registry
' Parameters:
' lHive - Registry hive or root i.e. HKEY_LOCAL_MACHINE
' strKeyPath - Key path for the Registry key to read
' (like "SOFTWARE\Microsoft\WindowsNT\CurrentVersion")
' strValueName - Name of the registry value to read (like "SoftwareType")
'
' Returns:
' The value of the registry key specified. "Nothing" if it fails.
' Callee needs to handle null value return.
'=============
Public Function ReadRegistryStringValue(ByVal lHive, ByVal strKeyPath, ByVal strValueName)

Dim oReg
Dim strValueData

'Get registry provider object
Call LogMessage(DBG_TRACE, "Connecting to WMI Registry : " + "winmgmts:\\"+ ScriptContext.TargetComputer+ "\root\default:StdRegProv")
Set oReg = WMIGetObject("winmgmts:\\"+ ScriptContext.TargetComputer+ "\root\default:StdRegProv")

'Read from value from registry
if oReg.GetStringValue(lHive, strKeyPath, strValueName, strValueData) = 0 Then
Call LogMessage(DBG_TRACE, "Value of Registry Key: " + strKeyPath + "\" + strValueName + " = " + strValueData)
ReadRegistryStringValue = strValueData
Else
Call LogMessage(DBG_ERROR, "Reading Registry Key: " + strKeyPath + "\" + strValueName + " Failed!" )
ReadRegistryStringValue = Empty
End If

Set oReg = Nothing

End Function

'=============
' Method: ReadRegistryDWORDValue
' Description: Used to read DWORDs from the registry
' Parameters:
' lHive - Registry hive or root i.e. HKEY_LOCAL_MACHINE
' strKeyPath - Key path for the Registry key to read
' (like "SOFTWARE\Microsoft\WindowsNT\CurrentVersion")
' strValueName - Name of the registry value to read (like "SoftwareType")
'
' Returns:
' The value of the registry key specified. "Nothing" if it fails.
' Callee needs to handle null value return.
'=============
Public Function ReadRegistryDWORDValue(ByVal lHive, ByVal strKeyPath, ByVal strValueName)

Dim oReg
Dim lValueData

'Get registry provider object
Call LogMessage(DBG_TRACE, "Connecting to WMI Registry : " + "winmgmts:\\"+ ScriptContext.TargetComputer+ "\root\default:StdRegProv")
Set oReg = WMIGetObject("winmgmts:\\"+ ScriptContext.TargetComputer+ "\root\default:StdRegProv")

'Read value from registry
if oReg.GetDWORDValue(lHive, strKeyPath, strValueName, lValueData) = 0 Then
Call LogMessage(DBG_TRACE, "Value of Registry Key: " + strKeyPath + "\" + strValueName + " = " &amp; lValueData)
ReadRegistryDWORDValue = lValueData
Else
Call LogMessage(DBG_ERROR, "Reading Registry Key: " + strKeyPath + "\" + strValueName + " Failed!" )
ReadRegistryDWORDValue = Empty
End If

Set oReg = Nothing

End Function

'=============
' Method: EnumRegistryKeys
' Description: Used to enumerate registry keys under a given path
' Parameters:
' lHive - Registry hive or root i.e. HKEY_LOCAL_MACHINE
' strKeyPath - Key path for the Registry key to read
' (like "SOFTWARE\Microsoft\WindowsNT\CurrentVersion")
' Returns:
' The list of registry keys found under the path. "null" if the list is empty
'=============
Public Function EnumRegistryKeys(ByVal lHive, ByVal strKeyPath)

Dim oReg
Dim arrKeys

'Get registry provider object
Call LogMessage(DBG_TRACE, "Connecting to WMI Registry : " + "winmgmts:\\"+ ScriptContext.TargetComputer+ "\root\default:StdRegProv")
Set oReg = WMIGetObject("winmgmts:\\"+ ScriptContext.TargetComputer + "\root\default:StdRegProv")

'Enumerate keys in registry
if oReg.EnumKey(lHive, strKeyPath, arrKeys) = 0 Then
Call LogMessage(DBG_TRACE, "Found [" + arrKeys(0) + "] key in path : " + strKeyPath )
EnumRegistryKeys = arrKeys
Else
Call LogMessage(DBG_ERROR, "Error enumerating Registry Keys under path : " + strKeyPath )
End If

Set oReg = Nothing

End Function

'=============
' Method: CheckRegistryKeyAccess
' Description: Used to check permissions access to a registry key
' Parameters:
' lHive - Registry hive or root i.e. HKEY_LOCAL_MACHINE
' strKeyPath - Key path for the Registry key to check access
' (like "SOFTWARE\Microsoft\WindowsNT\CurrentVersion")
' lAccess - required permissions i.e. KEY_QUERY_VALUE + KEY_SET_VALUE
' Returns:
' True if the specified permissions are present on the registry key else false.
'=============
Public Function CheckRegistryKeyAccess(ByVal lHive, ByVal strKeyPath, ByVal lAccess)

Dim oReg
Dim bGranted

'Get registry provider object
Call LogMessage(DBG_TRACE, "Connecting to WMI Registry : " + "winmgmts:\\"+ ScriptContext.TargetComputer+ "\root\default:StdRegProv")
Set oReg = WMIGetObject("winmgmts:\\"+ ScriptContext.TargetComputer + "\root\default:StdRegProv")

'Check access to the specified registry key
if oReg.CheckAccess(lHive, strKeyPath, lAccess, bGranted) = 0 Then
Call LogMessage(DBG_TRACE, "Required access present on registry key : " + strKeyPath )
CheckRegistryKeyAccess = bGranted
Else
Call LogMessage(DBG_ERROR, "Error checking access on registry keys : " + strKeyPath )
CheckRegistryKeyAccess = False
End If

Set oReg = Nothing

End Function

'=============
' Method: CheckRegistryKeyExists
' Description: Used to check existence of a registry key
' Parameters:
' lHive - Registry hive or root i.e. HKEY_LOCAL_MACHINE
' strKeyPath - Key path for the Registry key to check access
' (like "SOFTWARE\Microsoft\WindowsNT\CurrentVersion")
' Returns:
' True if the registry key exists else false.
'=============
Public Function CheckRegistryKeyExists(ByVal lHive, ByVal strKeyPath)

CheckRegistryKeyExists = CheckRegistryKeyAccess(lHive, strKeyPath, KEY_QUERY_VALUE)

End Function

'=============
' Method: CheckRegistryKeyStringValueExists
' Description: Used to check existence of a registry key string value
' Parameters:
' lHive - Registry hive or root i.e. HKEY_LOCAL_MACHINE
' strKeyPath - Key path for the Registry key to check access
' (like "SOFTWARE\Microsoft\WindowsNT\CurrentVersion")
' Returns:
' True if the string value exists else false.
'=============
Public Function CheckRegistryKeyStringValueExists(ByVal lHive, ByVal strKeyPath, ByVal strValueName)

Dim strValue

strValue = ReadRegistryStringValue(lHive, strKeyPath, strValueName)

If IsEmpty(strValue) Then
CheckRegistryKeyStringValueExists = False
Else
CheckRegistryKeyStringValueExists = True
End If

End Function

'=============
' Method: CheckRegistryKeyDWORDValueExists
' Description: Used to check existence of a registry key DWORD value
' Parameters:
' lHive - Registry hive or root i.e. HKEY_LOCAL_MACHINE
' strKeyPath - Key path for the Registry key to check access
' (like "SOFTWARE\Microsoft\WindowsNT\CurrentVersion")
' Returns:
' True if the DWORD value exists else false.
'=============
Public Function CheckRegistryKeyDWORDValueExists(ByVal lHive, ByVal strKeyPath, ByVal strValueName)

Dim lValue

lValue = ReadRegistryDWORDValue(lHive, strKeyPath, strValueName)

If IsEmpty(lValue) Then
CheckRegistryKeyDWORDValueExists = False
Else
CheckRegistryKeyDWORDValueExists = True
End If

End Function

End Class


'=============
' Function: CheckWow64RegistryKeyExists
' Description: Used to check existence of registry key
'
' HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node
'
' Parameters: None
' Returns: True if the registry key exists else false.
'=============
Public Function CheckWow64RegistryKeyExists()

Dim oReg
Dim bGranted
Dim strKeyPath
Dim HKEY_LOCAL_MACHINE
Dim KEY_QUERY_VALUE

ScriptContext.Echo "Checking for Wow64 registry key."

'Get registry provider object
ScriptContext.Echo "Connecting to WMI Registry : " + "winmgmts:\\"+ ScriptContext.TargetComputer + "\root\default:StdRegProv"
Set oReg = WMIGetObject("winmgmts:\\"+ ScriptContext.TargetComputer + "\root\default:StdRegProv")

'Check access to the specified registry key
HKEY_LOCAL_MACHINE = &amp;H80000002
strKeyPath = "SOFTWARE\Wow6432Node\Microsoft\SMS"
KEY_QUERY_VALUE = &amp;H1

if oReg.CheckAccess(HKEY_LOCAL_MACHINE, strKeyPath, KEY_QUERY_VALUE, bGranted) = 0 Then
ScriptContext.Echo "Wow64 is present on this computer; found registry key : " + strKeyPath
CheckWow64RegistryKeyExists = bGranted
Else
ScriptContext.Echo "Wow64 is not present on this computer; could not access registry key : " + strKeyPath
CheckWow64RegistryKeyExists = False
End If

Set oReg = Nothing

End Function


'=============
' Function: WMIGetObject
' Description: Returns an object of type SWbemObjectSet
' Parameters:
' sNamespace - A WMI Namespace (ex. winmgmts:\\COMPUTERNAME\ROOT\cimv2).
'=============
Function WMIGetObject(sNamespace)
Dim oWMI
Dim nErrNumber, sErrDescription

On Error Resume Next
Set oWMI = GetObject(sNamespace)
nErrNumber = Err.Number
sErrDescription = Err.Description
On Error Goto 0
If IsEmpty(oWMI) Or nErrNumber &lt;&gt; 0 Then
ScriptContext.Echo "Unable to open WMI Namespace " &amp; sNamespace
Err.Raise 9100, GET_WMI_NO_NAMESPACE_SOURCE(sNamespace), GET_WMI_NO_NAMESPACE_DESCRIPTION(nErrNumber, sErrDescription)
End If

Set WMIGetObject = oWMI

Set oWMI = Nothing
End Function


'=============
' Function: WMIGetInstance
' Description: Returns an object of type SWbemObjectSet
' Parameters:
' sNamespace - A WMI Namespace (ex. winmgmts:\\COMPUTERNAME\ROOT\cimv2).
' sInstance - A WMI Namespace Instance (ex. Win32_OperatingSystem)
'=============
Function WMIGetInstance(sNamespace, sInstance)
Dim oWMI, oInstance
Dim nErrNumber, sErrDescription

On Error Resume Next
Set oWMI = GetObject(sNamespace)
nErrNumber = Err.Number
sErrDescription = Err.Description
On Error Goto 0
If IsEmpty(oWMI) Or nErrNumber &lt;&gt; 0 Then
ScriptContext.Echo "Unable to open WMI Namespace " &amp; sNamespace
Err.Raise 9100, GET_WMI_NO_NAMESPACE_SOURCE(sNamespace), GET_WMI_NO_NAMESPACE_DESCRIPTION(nErrNumber, sErrDescription)
End If

On Error Resume Next
Set oInstance = oWMI.InstancesOf(sInstance)
nErrNumber = Err.Number
sErrDescription = Err.Description
On Error Goto 0
If IsEmpty(oInstance) Or nErrNumber &lt;&gt; 0 Then
ScriptContext.Echo "The class name '" &amp; sInstance &amp; "' returned no instances. Error:" &amp; nErrNumber &amp; ", " &amp; sErrDescription &amp; "."
Err.Raise 9100, GET_WMI_NO_INSTANCES_SOURCE(sInstance), GET_WMI_NO_INSTANCES_DESCRIPTION(nErrNumber, sErrDescription)
End If

'Determine if we queried a valid WMI class - Count will return 0 or empty
On Error Resume Next
Dim nInstanceCount
nInstanceCount = oInstance.Count
nErrNumber = Err.Number
sErrDescription = Err.Description
On Error Goto 0
If nErrNumber &lt;&gt; 0 Then
ScriptContext.Echo "The class name '" &amp; sInstance &amp; "' did not return any valid instances. Error:" &amp; nErrNumber &amp; ", " &amp; sErrDescription &amp; "."
Err.Raise 9100, GET_WMI_NO_VALID_INSTANCES_SOURCE(sInstance), GET_WMI_NO_VALID_INSTANCES_DESCRIPTION(nErrNumber, sErrDescription)
End If

Set WMIGetInstance = oInstance

Set oInstance = Nothing
Set oWMI = Nothing
End Function


'=============
' Function: WMIExecQuery
' Description: Returns an object of type SWbemObjectSet
' Parameters:
' sNamespace - A WMI Namespace (ex. winmgmts:\\COMPUTERNAME\ROOT\cimv2).
' sQuery - A SQL Query (ex. SELECT * FROM Win32_OperatingSystem)
'=============
Function WMIExecQuery(sNamespace, sQuery)
Dim oWMI, oQuery
Dim nErrNumber, sErrDescription

On Error Resume Next
Set oWMI = GetObject(sNamespace)
nErrNumber = Err.Number
sErrDescription = Err.Description
On Error Goto 0

If IsEmpty(oWMI) Or nErrNumber &lt;&gt; 0 Then
ScriptContext.Echo "Unable to open WMI Namespace " &amp; sNamespace
Err.Raise 9100, GET_WMI_NO_NAMESPACE_SOURCE(sNamespace), GET_WMI_NO_NAMESPACE_DESCRIPTION(nErrNumber, sErrDescription)
End If

On Error Resume Next
Set oQuery = oWMI.ExecQuery(sQuery)
nErrNumber = Err.Number
sErrDescription = Err.Description
On Error Goto 0
If IsEmpty(oQuery) Or nErrNumber &lt;&gt; 0 Then
ScriptContext.Echo "The Query '" &amp; sQuery &amp; "' returned an invalid result set. Error:" &amp; nErrNumber &amp; ", " &amp; sErrDescription &amp; "."
Err.Raise 9100, GET_WMI_QUERY_NO_RESULTS_SOURCE(sQuery), GET_WMI_QUERY_NO_RESULTS_DESCRIPTION(nErrNumber, sErrDescription)
End If

'Determine if we queried a valid WMI class - Count will return 0 or empty
On Error Resume Next
Dim nInstanceCount
nInstanceCount = oQuery.Count
nErrNumber = Err.Number
sErrDescription = Err.Description
On Error Goto 0
If nErrNumber &lt;&gt; 0 Then
ScriptContext.Echo "The Query '" &amp; sQuery &amp; "' did not return any valid instances. Error:" &amp; nErrNumber &amp; ", " &amp; sErrDescription &amp; "."
Err.Raise 9100, GET_WMI_QUERY_NO_VALID_INSTANCES_SOURCE(sQuery), GET_WMI_QUERY_NO_VALID_INSTANCES_DESCRIPTION(nErrNumber, sErrDescription)
End If

Set WMIExecQuery = oQuery

Set oQuery = Nothing
Set oWMI = Nothing

End Function


'******************************************************************************
' Name: IsEventTracingEnabled
'
' Purpose: Returns the state of the EventTracingEnabled registry setting.
' This setting is directs scripts raise additional tracing MOM
' events i.e. start and completion events.
'
' Checks for the EventTracingEnabled registry value under the
' following registry paths. If the DWORD values exists, it is read.
'
' HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft Operations Manager
' HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft Operations Manager
'
' Parameters: None
'
' Returns: True if the value exists and is set to 1 else False.
'
Function IsEventTracingEnabled()

Dim strError
Dim lEventTracingEnabled

Dim objShell


On Error Resume Next


LogMessage DBG_TRACE, "Checking EventTracingEnabled registry value."

'Create the WSH Shell object for accessing the registry.
'=======================================================

Set objShell = CreateObject("WScript.Shell")

If Err.number &lt;&gt; 0 Then
IsEventTracingEnabled = False
Exit Function
End If

'Read the EventTracingEnabled value from under the MOM key.
'==========================================================

lEventTracingEnabled = objShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft Operations Manager\EventTracingEnabled")

If IsEmpty(lEventTracingEnabled) Then

lEventTracingEnabled = objShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft Operations Manager\EventTracingEnabled")

End If

'Return the appropriate value.
'=============================

If IsEmpty(lEventTracingEnabled) Then

strError = GetErrorString(Err)
LogMessage DBG_TRACE, "Failed to read EventTracingEnabled registry value." &amp; strError

IsEventTracingEnabled = False

Else

LogMessage DBG_TRACE, "EventTracingEnabled registry value is '" &amp; lEventTracingEnabled &amp; "'."

If (lEventTracingEnabled = 1) Then
IsEventTracingEnabled = True
Else
IsEventTracingEnabled = False
End If

End If

Set objShell = Nothing

Err.Clear

End Function</Script></Body>
<Language>VBScript</Language>
<Name>ConfigMgr 2007 Monitor Site Maintenance Tasks</Name>
<Parameters>
<Parameter>
<Name>MaximumTaskDuration</Name>
<Value>$Config/Parameters/MaximumTaskDuration$</Value>
</Parameter>
</Parameters>
<ManagementPackId>[Microsoft.SystemCenter.ConfigurationManager.2007,,1.0.0.1]</ManagementPackId>
</WriteAction>
</MemberModules>
<Composition>
<Node ID="RunScriptAction"/>
</Composition>
</Composite>
</ModuleImplementation>
<InputType>SystemLibrary!System.BaseData</InputType>
</WriteActionModuleType>