Part 1: Probe Action Modules
In the following example we will use a PowerShell script to check for a string in a file. If the string is found we alter the health state to “Unhealthy”, otherwise the health state is “Healthy”.
param([string]$file, [string]$errorText, $debug, $executedAsTask)
if ($debug -ne "true"){$debug = [bool]$false}else{$debug = [bool]$true}
if ($executedAsTask -ne "true"){$executedAsTask = [bool]$false}else{$executedAsTask = [bool]$true}
$Script:API = new-object -comObject "MOM.ScriptAPI"
$Script:Bag = $Script:API.CreatePropertyBag()
$Script:LOG_ERROR = 1
$Script:LOG_WARNING = 2
$Script:LOG_INFORMATION = 4
$Script:ScriptName = "code4ward.Sample.PowerShellMonitor.ps1"
$Script:Arguments = "Received Arguments:`rFile = $file`rErrorText = $errorText`rDebug = $debug`rExecutedAsTask = $executedAsTask"
function Write-DebugInfo([string] $msg)
{
if ($debug)
{
$Script:API.LogScriptEvent("$ScriptName",100,$Script:LOG_INFORMATION,"`r$Arguments`r`r$msg")
}
}
function Write-ErrorInfo([string] $msg)
{
$Script:API.LogScriptEvent("$ScriptName",500,$Script:LOG_ERROR,"`r$Arguments`r`r$msg")
}
Write-DebugInfo "Script started..."
if ($file.Trim().Length -gt 0)
{
$FileExists = (Test-Path $file)
}
else
{
Write-ErrorInfo "No file was specified."
return
}
if (-not $FileExists)
{
Write-ErrorInfo = "File '$file' not found."
return
}
$File = Get-Item $file
[string]$FileContent = @()
foreach ($Line in Get-Content $File)
{
$FileContent += "`r$Line"
}
if ($errorText.Trim().Length -gt 0)
{
if ($FileContent.Contains($errorText))
{
$Script:Bag.AddValue("Status","ERROR")
$Script:Bag.AddValue("MessageText","Error text '$errorText' found in file '$file'.")
}
else
{
$Script:Bag.AddValue("Status","OK")
$Script:Bag.AddValue("MessageText","Error text '$errorText' not found in file '$file'.")
}
if ($executedAsTask)
{
$Script:Bag.AddValue("AdditionalStuff","goes here")
}
}
else
{
Write-ErrorInfo "No error text specified"
}
#$Script:API.Return($Bag)
$Script:Bag
Write-DebugInfo "Script ended..."
Note that at the very end of the script we just write $Script:Bag and NOT $Script:API.Return($Bag) as you might expect. However, I left this line commented in the script for testing because only the return command will generate the property bag data in the console which is useful for testing and debugging but the Module we are using soon will not work with the Return method.
How will this script be used?
We create one module holding the script and it’s configuration. This module will be used for our data source (scheduled) and the monitor type for “On Demand Detection” (enabling the recalculate health functionality). We create a second module wrapped around our first module with a different configuration to use the same script as a diagnostic or agent task. The reason for the second module is to illustrate the concept of wrapping modules providing the same functionality but with different configuration. In our case, the overridable parameters and the configurable parameters will be different in the second module.
The documentation on Technet is getting better and better. For a module reference visit:http://technet.microsoft.com/en-us/library/dd391800.aspx
What are the parameters for?
File: specify the full path to the file to check for
ErrorText: the string we are looking for and generate an alert
Debug: can be “true” or “false”. If true additional information will be published to the event log.
ExecutedAsTask: in this example only used to illustrate that we can use the same script for different modules/tasks. In a real world script you may use this to provide an extended property bag to pass more information to your operator.
There’s no error handling in this script, therefore it is far from production quality and only used to show the concepts of a PowerShell 2-state-script-monitor!
Creating the Modules

Open up the “Authoring Console” (needs to be installed separately and can be found on the SCOM R2 media) and let’s create a new management pack using File->New…
The MP ID is: code4ward.Sample.PowerShellMonitor
The Display Name is: code4ward Sample PowerShell Monitor
Now let’s navigate to the Type Library space, and select Type LibraryModule TypesProbe Actions in the tree view.

Right-click in the Probe Actions and select New->Composite Probe Action.
Type in an ID:code4ward.Sample.PowerShellMonitor.Probe.CheckFileContent
Type in a Name: Check File Content

Change to the Member Modules tab and click on Add…
Now look for the PowerShellPropertyBagProbe module, select it and specify an ID for the module like Probe
Click OK. Back in the Member Modules tab click on Edit and again in the configuration window click again on Edit and choose an external editor (like Notepad) if not already chosen.
Replace the XML stuff inside the element with the code below and not that the script body needs to be filled as well with the script at the beginning of this post.
code4ward.Sample.PowerShellMonitor.ps1 File $Config/File$ ErrorText $Config/ErrorText$ Debug $Config/Debug$ ExecutedAsTask $Config/ExecutedAsTask$ 300
After you closed the configuration dialog, select Module Output in the drop down list in the Next Module column.

Now let’s switch to the Configuration Schema tab. Use the Add…button on the bottom of the dialog to create the parameters as shown in the screenshot. Watch out for the type drop down list and ensure that the type is correct for each parameter.

Now we move on to the Overridable Parameters tab and add all of our parameters to the list. When you click the Add… button, a menu shows you all available parameters we defined in the previous tab. Just select one after the other and to keep it simple we call them the same as defined in the configuration. (The name you specify here will appear in the override dialog.)
Also, always verify the data type in the Configuration Element column.

In the Data Types tab we need to check the radio button This module requires input data.

Last but not least, we change the Accessibility proerty to Public. This is optional and may be useful when you seal your MP and provide these modules to use in other MPs. Now let’s hit OK and see if we can successfully close this dialog. If you get an exception, you may have a typo or a wrong order of parameters, which is also very important.

As mentioned before we will create a module based on the just created one to provide a different configuration.
Again, right-click on the Probe Actions pane and select New->Composite Probe Action…
This one gets the ID:code4ward.Sample.PowerShellMonitor.Probe.CheckFileContentAsTask
The name is: Check File Content as Task

In the Member Modules tab we click on Add… again but this time we choose the module we just created.

Now we will see the configuration we just created in the previous module. Except for the ExecutedAsTask configuration we use the little arrow button on the right side of each value and hit promote.
This means File, ErrorText and Debug will be passed to the module using our configuration (where we actually use this module) and theExecutedAsTask will be set to true.
Click on OK and don’t forget to set the Module Output in the Next Module column.

The Configuration Schema tab should know all your config settings for this module but always check for the right data type! In our case you need to explicitly set Debug to Boolean. I guess this is a bug in the Authoring Console because for some types this works automatically for some others not. Maybe future releases of the Authoring Console will be more reliable in this regard.

Next tab Overridable Parameters. In this derived module we only allow to override the Debug value.
Because the task will be available in the diagnostics of the monitor, we already know which File and what ErrorText we want to check.

As in the previous module, we need to set the Input Data right in theData Types tab.
Co-Founder and CEO of Royal Apps GmbH and Windows lead developer for Royal TS, a multi platform, multi protocol remote management solution, for Windows, macOS and mobile supporting RDP, VNC, SSH, Telnet, and many more.
Long time Microsoft MVP (2010-2020) supporting communities on- and offline as well as speaking at user groups and conferences about DevOps and other software development topics.