Part 2 - Getting Data into a Script

By Brian Wren, Senior Consultant, Microsoft Consulting Services (Southern California)

This article is the second of a four-part series on writing scripts in Microsoft Operations Manager (MOM). The theme of the series is to compare scripts in MOM to those written for Windows Script Host in order to leverage the large amount of knowledge and materials already focused on scripts for Windows Script Host.

Part 1 - The Basics

Introduces the concepts behind MOM scripts compared to those in Windows Script Host and the common and different objects used by each. You will learn how to get output data from a script into the MOM workflow.

Part 2 - Getting Data into a Script

Focuses on getting data into a MOM script. This includes working with parameters and retrieving information from the MOM object that launches the script.

Part 3 - Writing and Debugging

Insight into the logistics of writing and debugging a script in MOM. This article covers the use of different editors and utilities for performing these functions.

Part 4 - Best Practices

Discussion of best practices and answers to general questions, such as: When should you generate an alert as opposed to an event with a MOM script? How complex should a MOM script be before you break it into multiple parts? What about security?

On This Page

Getting Data into a MOM Script
Parameters (Instead of Arguments)
Providing Script Parameter Value from a Rule
Providing Script Parameter Value from a Task
Accessing the Invoking MOM Object
Event Parameters
Disable a User Account Example
Conclusion

Getting Data into a MOM Script

With Windows Script Host (WSH), you typically use WScript.Arguments to pass information into a script. The functional equivalent in MOM is ScriptContext.Parameters, which allows you to provide values for defined parameters in the rule calling the script. Other methods of getting data into a MOM script, which have no direct WSH equivalent (and which we’ll identify in a bit), allow us to pull information from the event, alert, or performance data object that initiated the script. Here in Part 2 of this four-part series we’ll cover each of these methods separately since there are distinct scenarios for each, and many scripts will use a combination of both.

Parameters (Instead of Arguments)

WSH scripts accept arguments using WScript.Arguments, while MOM scripts accept parameters using ScriptContext.Parameters. The two are almost direct equivalents, but with some minor differences. While WScript.Arguments simply returns an array of arguments, ScriptContext.Parameters requires us to call the Get method to retrieve each named parameter. We also need to define each parameter on the Parameters tab of the script in MOM before the script can use them, while WScript.Arguments will happily pick up anything you want to throw onto the command line.

A short example of ScriptContext.Parameters is shown below. This code accepts two script parameters (Parameter1 and Parameter2) and assigns them to simple variables that may be used in the script.

strParameter1 = ScriptContext.Parameters.Get("Parameter1")
strParameter2 = ScriptContext.Parameters.Get("Parameter2")

You can break this example into separate steps by first creating a Parameters object and then using the Get method on that object. The following snippet operates identically to the previous example.

Set objParams = ScriptContext.Parameters
strParameter1 = objParams.Get("Parameter1")
strParameter2 = objParams.Get("Parameter2")

Both of these pieces of sample code assume that the parameters are defined on the Parameters tab of the script (see Figure 1). Only parameters that have been defined in that dialog box may be used in the script.

You can assign a value to a script parameter when you define it, in which case that value will act as the default when the script is assigned to a rule. You will still have the option to set the value in any rule or task that launches the script.

This may sound a little confusing, but an example should clear things up. The following Terminate a Process WSH script has the name of the process to terminate - notepad.exe - hardcoded into the script.

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colProcessList = objWMIService.ExecQuery _
    ("Select * from Win32_Process Where Name = 'Notepad.exe'")

For Each objProcess in colProcessList
    objProcess.Terminate()
Next

Using this script, we would need a separate script for each process that we wanted to terminate, which is not very flexible. This script would be far more reusable if we provided the name of the process as an argument. In MOM, defining the process through a parameter would allow multiple rules to be defined that would use the same script but terminate a different process. We could also create a task that calls the script and allows the operator to provide the process name when the script is executed.

The modified script would look like the following.

strProcess = ScriptContext.Parameters.Get("ProcessName")

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colProcessList = objWMIService.ExecQuery _
    ("Select * from Win32_Process Where Name = '" & strProcess & "'")

For Each objProcess in colProcessList
    objProcess.Terminate()
Next

This would require that a parameter named ProcessName be defined on the script, and that a value for this parameter specifying the name of the process to terminate be defined on the rule or the task executing the script. We probably wouldn’t give this parameter a default value on the script since it wouldn’t really make sense to define a default process to terminate.

To extend our example a bit, let’s add a parameter to specify whether we want the script to generate an event. If we are going to terminate a process, we might provide an event specifying whether the process was actually found and how many instances of it were terminated. We’ll give the administrator the option of whether or not to have that event created. Because we typically do want an event in this situation, I’ll set the default value to True.

Figure 1 shows our two parameters defined in the Script Properties dialog box.

Terminate a Process

Figure 1. Parameters on Terminate a Process script.

The new script using both of our new parameters is shown below. I used the CBool function to convert the GenerateEvent parameter into a Boolean value of True or False. Like variables in VBScript, MOM event parameters are of the type variant, and in this case our True value would be read as a string. We want an actual True or False Boolean value, so we need to perform this conversion.

In order to create the MOM event, I’ll pull in our CreateEvent subroutine (that we saw in Part 1) and its related constants. We’re going to call the CreateEvent subroutine only if the GenerateEvent script parameter is True.

Const EVENT_TYPE_SUCCESS = 0
Const EVENT_TYPE_ERROR   = 1
Const EVENT_TYPE_WARNING = 2
Const EVENT_TYPE_INFORMATION = 4
Const EVENT_TYPE_AUDITSUCCESS = 8
Const EVENT_TYPE_AUDITFAILURE = 16

strProcessName = ScriptContext.Parameters.Get("ProcessName")
bolGenerateEvent = CBool(ScriptContext.Parameters.Get("GenerateEvent"))

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colProcessList = objWMIService.ExecQuery _
    ("Select * from Win32_Process Where Name = '" & strProcessName & "'")

For Each objProcess in colProcessList
        objProcess.Terminate()
Next

If bolGenerateEvent = True Then
        CreateEvent 100,EVENT_TYPE_INFORMATION, "Process Monitoring", _
"Terminated " & colProcessList.Count & " instances of process " _
 & strProcessName & "."
End If

Sub CreateEvent(intEventNumber,intEventType,strEventSource,strEventMessage)
        Set objEvent = ScriptContext.CreateEvent()
        objEvent.EventNumber = intEventNumber
        objEvent.EventType = intEventType 
        objEvent.EventSource = strEventSource
        objEvent.Message = strEventMessage
        ScriptContext.Submit objEvent
End Sub

That gives us our script - now we just need to launch it. This particular script is useful when called from either a rule or a task, so let’s look at the details of each.

Providing Script Parameter Value from a Rule

If we call our Terminate a Process script from an event rule, then we can provide the final values for the script parameters in the rule definition. To illustrate this, let’s assume that there is a particular process that we want to terminate immediately if we see it started. For the sake of example, let’s call this nasty process root.exe.

In order to launch our script from a rule, we need another rule that will detect whether the process root.exe has started. I don’t want to get off topic, but the easiest method in MOM of determining if a process was started is to use a WMI Events Provider. If you’re familiar with this concept, then you already know what I’m talking about. If not, you can simply copy the information shown in the provider in Figure 2 and use that provider for an event rule that launches the Terminate a Process script.

Process Start

Figure 2. WMI Event Provider to detect a process starting.

The details of an event using this provider and launching the Terminate a Process script are provided in Table 1 (it’s in the AKM too). Note that this event does not need any criteria. The WMI Event provider is already specifying the process we’re looking for and will launch the script anytime it sees that root.exe was started.

Table 1. Details of sample Event rule to detect and terminate a specified process.

Tab

Property

Value

General

Name

Process root.exe was detected and will be terminated.

Data Provider

Provider Name

Process root.exe started (WMI Event Provider)

Alert

Generate Alert

Checked

Alert

Alert Severity

Warning

Responses

Launch Script

Terminate a process

When you select the script to launch in the Responses tab of the rule definition, the default value for each parameter defined in the script (if a default value is defined) will be used for each parameter in the Launch a Script dialog box. If you want to change the default value (or provide a value in the case of no default), then click on the Edit Parameter button with the appropriate parameter highlighted. The script parameters for our test event are shown in Figure 3. I left the default for GenerateEvent but provided the value root.exe for ProcessName.

Paramter Value on a Rule

Figure 3. Specifying a parameter value on a rule.

If you want to test this, deploy the rule to any computer with the MOM agent. If you start any process on that computer called root.exe (just copy notepad.exe or some other small application to root.exe and run it), that process should automatically be closed within a few seconds and then a MOM alert generated.

Providing Script Parameter Value from a Task

Tasks give you two chances to provide values for script parameters. The first is when you create the task. Much like the definition of the parameter in the script itself, this defines a default for the task. Your other chance to modify the value is each time you execute the task.

Using our Terminate a Process script in a task is a natural progression from our List Process Owners example in Part 1. When analyzing a particular agent computer, we might execute List Process Owners from a task and identify a process that should not be running. In response to that information, we may want to launch another task to terminate the offending process. This is similar to the functionality that we achieved in the previous example calling the script from an event rule but in more of an ad-hoc nature.

To test out our Terminate a Process script in this fashion, create a task that launches the script. When you launch the task against an agent computer you are presented with the Launch Task Wizard which (after a couple of Next clicks) will present you with the list of parameters for the script. At that time, you can specify the name of the process you’re interested in terminating (as shown in Figure 4).

Execution for a Task

Figure 4. Defining a parameter value on script execution for a task.

This one is even easier to try out than running the script from a rule. Start a process called root.exe on an agent computer (you can just make a copy of Notepad.exe) and then launch the task against that computer. The process should be terminated within a few seconds and a MOM alert generated.

Accessing the Invoking MOM Object

Sometimes we can provide information to the script when we create the rule or task, and that’s when script parameters are useful. Things aren’t always that predictable though, and we sometimes need to get information from the object that invoked the launching of the script. Fortunately, ScriptContext provides us with three properties that give us access to these objects: Alert, Event, and PerfData. The trick is that at most only one of these objects will be valid at any given time, and in fact, none of them may be.

What happens if you run a script against the wrong object? For instance, maybe you wrote a script expecting it to be initiated by an event, so you appropriately used the Event object. Then you get a circumstance where it would make sense to launch the script in response to an alert rule instead. That Event object won’t exist if the script is called from an alert rule, and your script will fail.

To identify which type of MOM object initiated a script, the ScriptContext object provides the IsAlert, IsEvent, and IsPerfData methods. As their names would imply, these methods will return True or False depending on the type of object that initiated execution of the script. Figure 5 illustrates this concept.

Calling Object Properties

Figure 5. Calling Object Properties.

So if, as in our example, your script was designed to execute in response to only a particular type of object, you can use the appropriate method to determine whether to execute the code or create an error event saying that the script was launched incorrectly. Another scenario might be that your script is able to execute successfully in response to either an event or an alert. In that case you might use the IsEvent and IsAlert methods to determine which block of code to execute, as shown in the pseudo code below.

If ScriptContext.IsEvent = True Then
    Set objEvent = ScriptContext.Event
    <Code using objEvent>
Else If ScriptContext.IsAlert = True Then
    Set objAlert = ScriptContext.Alert
    <Code using objAlert>
Else
    <Create an error event saying that the script isn’t allowed to be
     executed by a performance rule or a task.> 
End If

As usual, let’s illustrate these concepts by example. I’m going to leverage the Performance Data example that we used in Part 1. That script creates a piece of performance data with the size of a specified file. Suppose we wanted to set a threshold on that performance counter and move the file to an archive when it exceeds a certain size.

We can achieve this functionality by using the threshold rule defined in Table 5 in Part 1. That rule will generate an alert if the size of the file reaches 1 MB. Instead of issuing an alert though, let’s change the rule to fire a script in response. Let’s also start getting a little more sophisticated and get this rule to fire for any log file instead of hardcoding a static name. The details of the new rule are in Table 2 with the modified details in bold.

Table 2 . Details of Performance Rule to launch File Move script.

Tab

Property

Value

General

Name

The size of an application log has exceeded its threshold value. File will be moved to archive.

Data Provider

Provider Name

Script-generated data

Criteria

Instance

Matches wildcard ‘c:\logs\*’

Criteria

Object

equals ‘File’

Criteria

Counter

equals ‘File Size’

Threshold

the sampled value

Checked

Threshold

Greater than the following value

1000000

Alert

Generate alert

Unchecked

Responses

Response

TechNet: Scripting MOM: Move File
(Arbitrary script name. Feel free to use a name of your choice.)

Responses

Type

Script

This will cause the rule to fire for any file with a path starting with “c:\logs” or, put in common terms, any file in the c:\logs directory. You’re not reading this article because you’re interested in processing rules though - you want to see the script. We can start with the Move a File script from the Script Center.

Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.MoveFile "C:\FSO\ScriptLog.log" , "D:\Archive"

Pretty straightforward little script - as long as you know the path and filename of the file you want to move and where you want it to go. In our case, we aren’t going to know the name of the file until the script actually launches. Thanks to the rule we just created, we can count on our new move script (which we’re going to see in just a second) to launch in response to a performance counter, and we can get that performance counter using the ScriptContext.PerfData property. The file path happens to be in the InstanceName property of the PerfData object, and we can pass that name to the MoveFile method. Also, since we know how to use script parameters, we should provide the archive path through a script parameter. The new script looks like this:

Set objPerfData = ScriptContext.PerfData
strFilePath = objPerfData.InstanceName
strArchivePath = ScriptContext.Parameters.Get("ArchivePath")

Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.MoveFile strFilePath , strArchivePath

To be complete, let’s put in a bit of error checking. If this script happens to get called from an event rule, alert rule, or a task, it’s going to fail with an error kind of like Figure 6.

Error Event

Figure 6. Error event from using incorrect object.

This error is created when the script tries to access ScriptContext.PerfData but finds that it isn’t available. This is not a very descriptive error though. It would be preferable to check if the script was launched in response to perf data and provide an appropriate error message if it were called incorrectly. We can do that by using the IsPerfData method and creating an event communicating the error. To create the event, we’ll paste in the CreateEvent subroutine and constants from Part 1.

Const EVENT_TYPE_SUCCESS = 0
Const EVENT_TYPE_ERROR   = 1
Const EVENT_TYPE_WARNING = 2
Const EVENT_TYPE_INFORMATION = 4
Const EVENT_TYPE_AUDITSUCCESS = 8
Const EVENT_TYPE_AUDITFAILURE = 16

If ScriptContext.IsPerfData = False Then
        CreateEvent 200, EVENT_TYPE_ERROR, "Scripting MOM", "The script " & _
        ScriptContext.Name & " may only be executed in response to a performance rule. "
Else
        Set objPerfData = ScriptContext.PerfData
        strFilePath = objPerfData.InstanceName
        strArchivePath = ScriptContext.Parameters.Get("ArchivePath")

        Set objFSO = CreateObject("Scripting.FileSystemObject")
        objFSO.MoveFile strFilePath , strArchivePath
End If

Sub CreateEvent(intEventNumber,intEventType,strEventSource,strEventMessage)
        Set objEvent = ScriptContext.CreateEvent()
        objEvent.EventNumber = intEventNumber
        objEvent.EventType = intEventType 
        objEvent.EventSource = strEventSource
        objEvent.Message = strEventMessage
        ScriptContext.Submit objEvent
End Sub

Execute that script from a task or in response to an event or alert rule, and you should get a much more polite error message, as in Figure 7.

Customer Error Event

Figure 7. Custom error event from using incorrect object.

Execute the script in response to a performance rule, and the file should be moved to the archive location when it exceeds our specified threshold value.

Event Parameters

Probably the most common way for a script to be executed in MOM is in response to an event rule. We now know that we can use ScriptContext.Event to access the event information from the script, but the information we want is often buried deep in the event message. We can get the piece of data we want using a variety of the Mid, Left, Right, and InStr functions, but that might not be necessary.

Events often carry event parameters with them. Don’t confuse event parameters with script parameters that we covered in the first section of this article. Script parameters and their values are defined by the administrator creating the rule that launches the script, while event parameters are distinct pieces of data carried with some events generated by MOM.

A typical event in Windows is comprised of static text and a number of parameters with information specific to each occurrence of the event. For example, an event in the Security Event Log will usually have parameters such as user and domain names of the user account that initiated creation of the event. It is these event parameters that MOM scripts can access. The event message typically contains the parameter values, but they’ll usually be muddled up with that descriptive text. Accessing the parameters on their own would be a heck of a lot easier.

Disable a User Account Example

I was once asked by a customer to have MOM monitor for a user clearing the Security Event Log on a domain controller. If that action occurred, the offending user should have their user account disabled. The idea is that an administrative account may have been compromised, and the culprit is clearing the security log to cover their tracks. It turns out that this is a great scenario to illustrate the use of event parameters, and I’ll take the opportunity to present some work with Active Directory Services Interface (ADSI).

I’m about to throw out several concepts at once related to scripts working with Active Directory. These concepts may be new to you, and you can reference the Microsoft Windows 2000 Scripting Guide for a complete discussion on ADSI. ADSI makes sense to use for our event parameter example though because we commonly use event parameters to retrieve user account data, and you will very often be faced with challenges similar to what we’re about to address. If you’re not at all interested in ADSI, then you should still be able to follow the example for a clear demonstration on how to use event parameters.

One other thing to keep in mind is that this example will require the Action Account on the domain controller to have the authority to disable a user account in Active Directory. If you are unfamiliar with the concept of the Action Account, have a look at the MOM Security Guide.

Now let’s get on with our solution. We can detect a user clearing the Security Event Log by monitoring for security event 517. To see what this event looks like, create a collection rule and go ahead and clear the log. The resulting event looks something like Figure 8.

Sample Security Event

Figure 8. Sample Security Event.

You can see that the user name of the user who cleared the log is in the event description next to the text “Client User Name:” with the domain name just below it. I could try building a command using the InStr and Mid functions with the Message property of the Event object to get those values, but there is a much easier way. If you click on the Events tab of that same event, you’ll see the screen in Figure 9.

Sample Event Parameters

Figure 9. Sample Event Parameters.

These are the event parameters, and you can see that the user name and domain that we want are right there in parameters 4 and 5. It would be a heck of a lot easier to grab these values than to have to go digging for them in the message.

So how do you find out what parameters an event can carry and what value is in what position? You can refer to the documentation of the application that generated the event, or you can just create an event collection rule for the event you’re interested in - like we just did. You can then inspect the collected event for the information you want. Make sure that the option to collect all parameters is selected in the rule or no parameters will be collected - just the event itself.

Event parameters like this are common for security auditing events. The challenge we often encounter is that in order to get an Active Directory object using ADSI, we need the distinguished name of the object, which includes the entire OU and domain path. Audit events are typically going to give us only an account name and a domain name. Because of this, our script is going to have two steps - first, find the user object we need to disable and second, disable that user.

We can achieve our first task with the functionality provided by the Search for a User Account in Active Directory script. That script accepts a user account name and then reports whether or not the user was found in the directory.

strUserName = "kenmyer"
dtStart = TimeValue(Now())
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open "Provider=ADsDSOObject;"
 
Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection
 
objCommand.CommandText = _
    "<LDAP://dc=fabrikam,dc=com>;(&(objectCategory=User)" & _
         "(samAccountName=" & strUserName & "));samAccountName;subtree"
  
Set objRecordSet = objCommand.Execute
 
If objRecordset.RecordCount = 0 Then
    WScript.Echo "sAMAccountName: " & strUserName & " does not exist."
Else
    WScript.Echo strUserName & " exists."
End If
 
objConnection.Close

We need to modify this script to use our event parameters to retrieve the user account and domain name we’re interested in. In this case, those will be in parameters 4 and 5 of the event (which we know from looking at Figure 9). Also, instead of just reporting whether the user exists (which requires the use of WScript.Echo, a command we’re going to have to remove to run the script in MOM), we need to get the user’s distinguished name into a variable that we can use for the second step.

Once the user account is specified, we need to modify the line specifying the criteria for our search. We obviously have to change the domain name, but we also need to specify that we want the query to return the distinguishedName instead of the samAccountName. Finally, we need to add a line to get the distinguishedName from the result set of the query and assign it to a variable.

The modified version of the script follows:

Set objEvent = ScriptContext.Event
strUserName = objEvent.EventParameter(4)
dtStart = TimeValue(Now())
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open "Provider=ADsDSOObject;"
 
Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection
 
objCommand.CommandText = _
    "<LDAP://" & objEvent.EventParameter(5) & ">;(&(objectCategory=User)" & _
         "(samAccountName=" & strUserName & "));distinguishedName;subtree"
  
Set objRecordSet = objCommand.Execute
 
strDistinguishedName = objRecordset("distinguishedName")
 
objConnection.Close

Now that we have the distinguished name of the user, we can disable the account using the Disable a User Account script shown below.

Const ADS_UF_ACCOUNTDISABLE = 2
 
Set objUser = GetObject _
    ("LDAP://cn=myerken,ou=management,dc=fabrikam,dc=com")
intUAC = objUser.Get("userAccountControl")
 
objUser.Put "userAccountControl", intUAC OR ADS_UF_ACCOUNTDISABLE
objUser.SetInfo

This one will be a lot easier to modify than the user search. The modified script simply replaces the hardcoded distinguished name with a variable that we will be taking from the previous script. The modified version is as follows:

Const ADS_UF_ACCOUNTDISABLE = 2
 
Set objUser = GetObject _
    ("LDAP:// " & strDistinguishedName)
intUAC = objUser.Get("userAccountControl")
 
objUser.Put "userAccountControl", intUAC OR ADS_UF_ACCOUNTDISABLE
objUser.SetInfo

The final script is our modified Search for a User Account in Active Directory script immediately followed by our modified Disable a User Account script.

Set objEvent = ScriptContext.Event
strUserName = objEvent.EventParameter(4)
dtStart = TimeValue(Now())
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open "Provider=ADsDSOObject;"
 
Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection
 
objCommand.CommandText = _
    "<LDAP://" & objEvent.EventParameter(5) & ">;(&(objectCategory=User)" & _
         "(samAccountName=" & strUserName & "));distinguishedName;subtree"
  
Set objRecordSet = objCommand.Execute
 
strDistinguishedName = objRecordset.Fields ("distinguishedName")
 
objConnection.Close

Const ADS_UF_ACCOUNTDISABLE = 2
 
Set objUser = GetObject _
    ("LDAP:// " & strDistinguishedName)
intUAC = objUser.Get("userAccountControl")
 
objUser.Put "userAccountControl", intUAC OR ADS_UF_ACCOUNTDISABLE
objUser.SetInfo

Important: Before I tell you how to test this script, please be careful, as you have the potential to lock yourself out of the network. Either create a test user account to disable or have the Active Directory Users and Computers MMC sitting open so that you can immediately re-enable yourself.

You can try this script out by creating a rule similar to Table 3 and deploying it to one or more domain controllers. Just clear the Security Event Log, and you should find that your user account becomes disabled.

Table 3 - Details of event rule to detect disable a user account in response to clearing the Security Event Log

Tab

Property

Value

General

Name

Security Event Log was cleared. User account will be disabled.

Data Provider

Provider Name

Security

Criteria

From source

Security

Criteria

With event ID

517

Alert

Generate alert

Checked

Alert

Alert severity

Security Issue

Responses

Response

TechNet: Scripting MOM: Disable a User Account

Responses

Type

Script

To make this solution complete, it would be helpful to logoff the user once the account has been disabled. There isn’t much use in disabling a user account when the nefarious user is already logged on and free to continue wreaking havoc until he chooses to logoff. I’m not going to include that though because we’ve already come far enough in terms illustrating our primary concepts. It also makes the script that much more dangerous to test. If you are interested, you can find a script that will shut down a computer or just logoff the current user in the Microsoft Windows 2000 Scripting Guide. It’s just a matter of adding that script to the end of the one we just created.

One final disclaimer if I may. A savvy nefarious user would probably disable the MOM service prior to performing an action like clearing the Security Event Log. In that case our script would never fire. This is not intended to be a rock solid security enforcement example but rather one of a number of pieces of enforcement and auditing as part of an overall security plan. If the MOM service was disabled, however, we would be alerted in MOM to a failed heartbeat and probably start an investigation.

Conclusion

We now know how to make our MOM scripts more versatile and responsive by dynamically providing data to them. We can provide that data either through values defined on the calling rule or task, or we can have the script pick up elements of the calling object. Combined with the information in Part 1 of this series, you now should be able write some compelling scripts in MOM.

In Part 3, we are going to take a step back from the scripts themselves to discuss the process of writing and debugging a script for MOM. This will include techniques for writing the code and different methods for testing and troubleshooting.