SCOM – Script Based Monitor With Consecutive Samples

There have been more than a few times when I have been working to tune “noisy” alerts where I have run into custom console created script based monitors as the main culprits.  This is not surprising, as the console script based monitor template does not offer the consecutive threshold functionality.  With this being the case, we end up with scenarios where a script based monitor for the monitored KPI is alerting based on one sample, which is not ideal and can be VERY noisy.  So…I decided to create my own.

Let’s use a physical memory monitor as the example for this post as it seems to be a fairy regular requirement.  In most cases I have seen, a script based monitor is configured using a simple WMI based VB or PowerShell script that collects a data sample and alerts if the value is greater than x threshold.  In other cases the consecutive sample logic is in the script itself, but this can get a bit complicated.  I prefer to have the consecutive sample logic in the management pack code.  Let’s move on!

Let’s get started…

1. The first step is to create the script.  In this example, I am using a very basic PowerShell script that calculates physical memory using the WMI “TotalVisibleMemorySize” and “FreePhysicalMemory” property values (see below).  Once the physical memory value has been calculated, the value is stored in a property bag so that SCOM can consume the data.

script

2. Create the management pack.  The unfortunate part about authoring a custom monitor is…well…you have to know how to author.  That said, I will provide all of the sample code you need to create your own management pack with a physical memory monitor that alerts if the average of 3 samples is above the defined threshold, and a collection rule to allow for reporting against this KPI.  You can use this code as a reference point for creating other management packs, monitors, rules, etc. moving forward.  I prefer to use Visual Studio Authoring Extensions (VSAE) because it requires me to actually learn the code and provides code analysis which really helps to debug the MP.  I will post screenshots of each module below:

a. Data Source Module Type:

I am using a composite module consisting of a SimpleScheduler data source module and a ProbeAction module utilizing the PowerShellTriggerOnlyPropertyBag probe.  I am using the SimpleScheduler data source module to initiate the workflow at a scheduled interval and the probe action to execute the script.  The output from the script is passed to a property bag, which will subsequently be converted to performance data in the monitor type module.

TIP:  I am using the TriggerOnly probe because I am not passing parameters to my script.  If I was passing parameters to the script, I would use the PowerShellPropertyBag probe.

ConsecSampleDataSource

b. Monitor Type Module:

ConsecSampleMonitorType1

ConsecSampleMonitorType2

c.  Collection Rule:

ConsecSampleRulexml

d. Monitor:

ConsecSamplerMonitorxml

e. Display:

ConsecSampleDisplayxml

We now have a functioning monitor for Percent Physical Memory Used and a collection rule to enable reporting on this counter.  Let’s go to the console to ensure that the monitor initialized and we are collecting data…

The monitor has in fact initialized, so far so good!

ConsecSampleMonitor

Now let’s check to verify that the rule is collecting data…

Good to go!  We now have a fully functioning monitor and collection rule.

ConsecSampleCollectionRule1

There are several ways to achieve the goal of adding multiple sample logic to your custom monitors.  We could have used the System.ConsolidatorCondition Condition Detection Module (https://msdn.microsoft.com/en-us/library/ee809324.aspx) or for a simpler and effective method in SCOM 2012 we could use the new “matchcount” and “samplecount” parameters in the system.expressionfilter.  Scott Murray does a great job of explaining this here: http://sc.scomurr.com/scom-2012-system-expressionfilter-and-consolidation/

Full SAMPLE MP Code:

**SAMPLE ONLY**

<!–?xml version=”1.0″ encoding=”utf-8″?>

<ManagementPack SchemaVersion=”2.0″ ContentReadable=”true” xmlns:xsd=”http://www.w3.org/2001/XMLSchema“>

<Manifest>

<Identity>

<ID>Performance2012</ID>

<Version>1.0.0.1</Version>

</Identity>

<Name>Performance2012</Name>

<References>

<Reference Alias=”MSDL”>

<ID>Microsoft.SystemCenter.DataWarehouse.Library</ID>

<Version>7.1.10226.0</Version>

<PublicKeyToken>31bf3856ad364e35</PublicKeyToken>

</Reference>

<Reference Alias=”SC”>

<ID>Microsoft.SystemCenter.Library</ID>

<Version>7.0.8433.0</Version>

<PublicKeyToken>31bf3856ad364e35</PublicKeyToken>

</Reference>

<Reference Alias=”Windows”>

<ID>Microsoft.Windows.Library</ID>

<Version>7.5.8501.0</Version>

<PublicKeyToken>31bf3856ad364e35</PublicKeyToken>

</Reference>

<Reference Alias=”Health”>

<ID>System.Health.Library</ID>

<Version>7.0.8433.0</Version>

<PublicKeyToken>31bf3856ad364e35</PublicKeyToken>

</Reference>

<Reference Alias=”System”>

<ID>System.Library</ID>

<Version>7.5.8501.0</Version>

<PublicKeyToken>31bf3856ad364e35</PublicKeyToken>

</Reference>

<Reference Alias=”Perf”>

<ID>System.Performance.Library</ID>

<Version>7.0.8433.0</Version>

<PublicKeyToken>31bf3856ad364e35</PublicKeyToken>

</Reference>

</References>

</Manifest>

<TypeDefinitions>

<ModuleTypes>

<DataSourceModuleType ID=”Performance.Memory.DataSource.ModuleType” Accessibility=”Internal” Batching=”false”>

<Configuration>

<xsd:element name=”SyncTime” type=”xsd:string” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” />

<xsd:element name=”IntervalSeconds” type=”xsd:integer” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” />

<xsd:element name=”TimeoutSeconds” type=”xsd:integer” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” />

</Configuration>

<OverrideableParameters>

<OverrideableParameter ID=”IntervalSeconds” Selector=”$Config/IntervalSeconds$” ParameterType=”int” />

<OverrideableParameter ID=”TimeoutSeconds” Selector=”$Config/TimeoutSeconds$” ParameterType=”int” />

</OverrideableParameters>

<ModuleImplementation Isolation=”Any”>

<Composite>

<MemberModules>

<DataSource ID=”Scheduler” TypeID=”System!System.SimpleScheduler”>

$Config/IntervalSeconds$

<SyncTime />

<!–DataSource>

<ProbeAction ID=”Probe” TypeID=”Windows!Microsoft.Windows.PowerShellPropertyBagTriggerOnlyProbe”>

<ScriptName>Performance.PhysicalMemory.Monitortype.ps1</ScriptName>

<ScriptBody>

$WMIObject = Get-WmiObject -class win32_operatingsystem | select *

$api = New-Object -ComObject ‘MOM.ScriptAPI’

$memused=$WMIObject.TotalVisibleMemorySize – $WMIObject.FreePhysicalMemory

$mempercent=$memused/$WMIObject.TotalVisibleMemorySize

$mempercent=$mempercent * 100

$mempercent = “{0:N0}” -f $mempercent

$bag=$api.CreatePropertyBag()

$bag.addvalue(‘PercentUsage’,$mempercent)

#$api.return($bag) | out-file c:\temp\test.txt

$bag

</ScriptBody>

$Config/TimeoutSeconds$

</ProbeAction>

</MemberModules>

<Composition>

<Node ID=”Probe”>

<Node ID=”Scheduler” />

</Node>

</Composition>

</Composite>

</ModuleImplementation>

<OutputType>System!System.PropertyBagData</OutputType>

</DataSourceModuleType>

</ModuleTypes>

<MonitorTypes>

<UnitMonitorType ID=”Performance.PhysicalMemory.Monitortype” Accessibility=”Internal”>

<MonitorTypeStates>

<MonitorTypeState ID=”MemUtilizationNormal” NoDetection=”false” />

<MonitorTypeState ID=”MemUtilizationHigh” NoDetection=”false” />

</MonitorTypeStates>

<Configuration>

<xsd:element name=”SyncTime” type=”xsd:string” xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221; />

<xsd:element name=”IntervalSeconds” type=”xsd:int” xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221; />

<xsd:element name=”Threshold” type=”xsd:double” xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221; />

<xsd:element name=”TimeoutSeconds” type=”xsd:int” xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221; />

<xsd:element name=”ObjectName” type=”xsd:string” xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221; />

xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221; />

xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221; />

NumSamples” type=”xsd:int” xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221; />

</Configuration>

<OverrideableParameters>

<OverrideableParameter ID=”IntervalSeconds” Selector=”$Config/IntervalSeconds$” ParameterType=”int” />

<OverrideableParameter ID=”Threshold” Selector=”$Config/Threshold$” ParameterType=”double” />

<OverrideableParameter ID=”TimeoutSeconds” Selector=”$Config/TimeoutSeconds$” ParameterType=”int” />

<OverrideableParameter ID=”NumSamples” Selector=”$Config/NumSamples$” ParameterType=”int” />

</OverrideableParameters>

<MonitorImplementation>

<MemberModules>

<DataSource ID=”DS1″ TypeID=”Performance.Memory.DataSource.ModuleType”>

<SyncTime />

$Config/IntervalSeconds$

<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>

</DataSource>

<ConditionDetection ID=”Mapper” TypeID=”Perf!System.Performance.DataGenericMapper”>

<ObjectName>$Config/ObjectName$</ObjectName>

<CounterName>$Config/CounterName$</CounterName>

<InstanceName />

<Value>$Data/Property[@Name=’PercentUsage’]$</Value>

<!–ConditionDetection>

<ConditionDetection ID=”Average” TypeID=”Perf!System.Performance.AveragerCondition”>

<NumSamples>$Config/NumSamples$</NumSamples>

<!–ConditionDetection>

<ConditionDetection ID=”FilterOK” TypeID=”System!System.ExpressionFilter”>

<Expression>

<SimpleExpression>

<ValueExpression>

<XPathQuery Type=”Double”>Value

</ValueExpression>

<Operator>LessEqual</Operator>

<ValueExpression>

<Value Type=”Double”>$Config/Threshold$</Value>

</ValueExpression>

</SimpleExpression>

</Expression>

</ConditionDetection>

<ConditionDetection ID=”FilterNotOK” TypeID=”System!System.ExpressionFilter”>

<Expression>

<SimpleExpression>

<ValueExpression>

<XPathQuery Type=”Double”>Value</XPathQuery>

</ValueExpression>

<Operator>Greater</Operator>

<ValueExpression>

<Value Type=”Double”>$Config/Threshold$</Value>

</ValueExpression>

</SimpleExpression>

</Expression>

</ConditionDetection>

</MemberModules>

<RegularDetections>

<RegularDetection MonitorTypeStateID=”MemUtilizationNormal”>

<Node ID=”FilterOK”>

<Node ID=”Average”>

<Node ID=”Mapper”>

<Node ID=”DS1″ />

</Node>

</Node>

</Node>

<!–RegularDetection>

<RegularDetection MonitorTypeStateID=”MemUtilizationHigh”>

<Node ID=”FilterNotOK”>

<Node ID=”Average”>

<Node ID=”Mapper”>

<Node ID=”DS1″ />

</Node>

</Node>

</Node>

</RegularDetection>

</RegularDetections>

</MonitorImplementation>

</UnitMonitorType>

</MonitorTypes>

</TypeDefinitions>

<Monitoring>

<Rules>

<Rule ID=”Performance.PhysicalMemory.PercentUtilization.Collection” Enabled=”true” Target=”Windows!Microsoft.Windows.Computer” ConfirmDelivery=”false” Remotable=”true” Priority=”Normal” DiscardLevel=”100″>

<Category>PerformanceCollection</Category>

<DataSources>

<DataSource ID=”DataSource” TypeID=”Performance.Memory.DataSource.ModuleType”>

<SyncTime />

<IntervalSeconds>120</IntervalSeconds>

<TimeoutSeconds>120</TimeoutSeconds>

</DataSource>

</DataSources>

<ConditionDetection ID=”System.Performance.DataGenericMapper” TypeID=”Perf!System.Performance.DataGenericMapper”>

<ObjectName>Memory</ObjectName>

<CounterName>Percent Physical Memory Used</CounterName>

<InstanceName />

<Value>$Data/Property[@Name=’PercentUsage’]$</Value>

</ConditionDetection>

<WriteActions>

<WriteAction ID=”Microsoft.SystemCenter.CollectPerformanceData” TypeID=”SC!Microsoft.SystemCenter.CollectPerformanceData” />

<WriteAction ID=”Microsoft.SystemCenter.DataWarehouse.PublishPerformanceData” TypeID=”MSDL!Microsoft.SystemCenter.DataWarehouse.PublishPerformanceData” />

</WriteActions>

</Rule>

</Rules>

<Monitors>

<UnitMonitor ID=”Performance.PhysicalMemory.PercentUtilization” Accessibility=”Public” Enabled=”true” Target=”Windows!Microsoft.Windows.Computer” ParentMonitorID=”Health!System.Health.PerformanceState” Remotable=”true” Priority=”Normal” TypeID=”Performance.PhysicalMemory.Monitortype” ConfirmDelivery=”false”>

<Category>PerformanceHealth</Category>

<AlertSettings AlertMessage=”Performance.PhysicalMemory.PercentUtilization.Alert”>

<AlertOnState>Error</AlertOnState>

<AutoResolve>true</AutoResolve>

<AlertPriority>Normal</AlertPriority>

<AlertSeverity>Error</AlertSeverity>

<AlertParameters>

<AlertParameter1>$Target/Property[Type=”Windows!Microsoft.Windows.Computer”]/DNSName$</AlertParameter1>

<AlertParameter2>$Data/Context/Value$</AlertParameter2>

</AlertParameters>

</AlertSettings>

<OperationalStates>

<OperationalState ID=”UnderThreshold” MonitorTypeStateID=”MemUtilizationNormal” HealthState=”Success” />

<OperationalState ID=”OverThreshold” MonitorTypeStateID=”MemUtilizationHigh” HealthState=”Error” />

</OperationalStates>

<Configuration>

<SyncTime />

<IntervalSeconds>300</IntervalSeconds>

<Threshold>85</Threshold>

<TimeoutSeconds>300</TimeoutSeconds>

<ObjectName>Memory</ObjectName>

<CounterName>Percent Physical Memory Used</CounterName>

<Value>$Data/Value$</Value>

<NumSamples>3</NumSamples>

</Configuration>

</UnitMonitor>

</Monitors>

</Monitoring>

<Presentation>

<StringResources>

<StringResource ID=”Performance.PhysicalMemory.PercentUtilization.Alert” />

</StringResources>

</Presentation>

<LanguagePacks>

<LanguagePack ID=”ENU” IsDefault=”false”>

<DisplayStrings>

<DisplayString ElementID=”Performance2012″>

<Name>Performance Management Pack</Name>

<Description>Management pack for all custom performance monitoring</Description>

<!–DisplayString>

<DisplayString ElementID=”Performance.PhysicalMemory.PercentUtilization.Alert”>

<Name>Physical Memory Percent Utilization</Name>

<Description>

The Physical Memory Utilization is too high on {0}

The value {1} has exceeded the threshold over 3 conecutive samples

</Description>

<!–DisplayString>

<DisplayString ElementID=”Performance.Memory.DataSource.ModuleType”>

<Name>Performance Physical Memory Data Source Module</Name>

<!–DisplayString>

<DisplayString ElementID=”Performance.PhysicalMemory.Monitortype”>

<Name>Performance Physical Memory Monitor Type</Name>

<!–DisplayString>

<DisplayString ElementID=”Performance.PhysicalMemory.PercentUtilization”>

<Name>Percent Physical Memory Used</Name>

<Description>The Physical Memory Utilization is $Data/Context/Value$</Description>

</DisplayString>

<DisplayString ElementID=”Performance.PhysicalMemory.PercentUtilization” SubElementID=”UnderThreshold”>

<Name>UnderThreshold</Name>

</DisplayString>

<DisplayString ElementID=”Performance.PhysicalMemory.PercentUtilization” SubElementID=”OverThreshold”>

<Name>OverThreshold</Name>

</DisplayString>

<DisplayString ElementID=”Performance.PhysicalMemory.PercentUtilization.Collection”>

<Name>Percent Physical Memory Used Collection Rule</Name>

</DisplayString>

</DisplayStrings>

<KnowledgeArticles></KnowledgeArticles>

</LanguagePack>

</LanguagePacks>

</ManagementPack>

This posting is provided “AS IS” with no warranties.

 

Advertisements

One thought on “SCOM – Script Based Monitor With Consecutive Samples

Comments are closed.