Ok, this is not really simple. This article is about some more complex MP Authoring modules…. reader beware.
Sometimes when authoring MP’s, you want to take a value and change it using math. Possibly dividing by 1000 to change KB to MB, or multiplying times 100 to make a fraction turn into a Percentage. Whatever the reason, most people are forced to do this in a script. That’s fine, as the PowerShell module in SCOM is very efficient. However – you CAN do math inside a native module as well.
This module is documented here: https://docs.microsoft.com/en-us/previous-versions/system-center/developer/jj130157(v=msdn.10)
However, the documentation leaves a LOT of be desired. The best examples of this being used are here: https://docs.microsoft.com/en-us/previous-versions/system-center/developer/jj130534(v=msdn.10)
I’ll demonstrate a simple use.
I wanted to create a monitor, that shows the Total Percentage of Physical Memory available on a VM. We don’t really have a monitor for that. The closes thing we have in SCOM is the monitor for % Committed Bytes in Use. That’s a good one, because it shows us the consumption of the Physical Memory AND the Page file. However, sometimes customers would like to just focus on physical memory. Right or wrong – that’s what I am developing here.
So assume I have a VM with 16GB of memory, and 15Gb is used. My “Available KB” Memory counter from Perfmon is 1,000,000 KB. My “Physical Memory” property from the Windows Server Operating System class in SCOM is 16,000,000.
Here is the problem. If I divide 1,000,000 KB available by 16,000,000 KB total, I get 0.0625. What I want to record is “Percent”. So I need to multiple this times “100” to get 6.25% Memory Available.
I will start by collecting the perf value using the standard Performance Datasource, then dividing that value by the Class Property for Physical Memory using “ScaleBy”.
I wrote about how to use ScaleBy here: https://kevinholman.com/2010/07/27/how-to-monitor-a-process-on-a-multi-cpu-agent-using-scaleby/
So – here is what my MonitorType will look like:
Perf Datasource (to get the perf value and ScaleBy) > System.Computation Condition Detection (to multiply times 100) > System.ExpressionFilter Condition Detection to evaluate if the resulting Percentage is above or below the threshold.
Here is what my System.Computation Condition Detection looks like:
<ConditionDetection ID="ComputePercentage" TypeID="System!System.Computation"> <NumericValue> <Product> <NumericValue> <XPathQuery Type="Double">Value</XPathQuery> </NumericValue> <NumericValue> <Value>100</Value> </NumericValue> </Product> </NumericValue> </ConditionDetection>
“Product” simply means multiplication. See all your options here: https://docs.microsoft.com/en-us/previous-versions/system-center/developer/jj130534(v=msdn.10)
“Value” in this case – is what I was handed off as the value from the previous module – which was the System.Performance.DataProvider
Here is what my MonitorType RegularDetection looks like. You can see it starts with the Perf Datasource, then System.Computation, then an Expression evaluation, then in this case I actually finish with a Probe module (PowerShell) to go get the top consuming memory processes, which we can add to the alert, which is nice.
<RegularDetection MonitorTypeStateID="Unhealthy"> <Node ID="ProbePS"> <Node ID="CDFreeMemoryLow"> <Node ID="ComputePercentage"> <Node ID="DSPerf" /> </Node> </Node> </Node> </RegularDetection>
What about rules?
I’m so glad you asked. We can also use this in rules, in a similar fashion. For a rule, this is a little more complicated, because rules are only allowed to use a single ConditionDetection. Therefore, we need to make a Composite Datasource that includes the Perf DS, along with the multiple Condition Detections. The reason we need multiple Condition Detections is because the System.Computation module outputs data of type: System.ComputationData. We actually have to map that back into System.Performance.Data using a special Perf Mapper Condition Detection. So for a rule, it will look like:
Perf Datasource > System.Computation ConditionDetection > System.Performance.DataGenericMapper ConditionDetection to “map” the output from the previous Module back into Performance data, so it can be collected.
Here is the full example datasource:
<DataSourceModuleType ID="Windows.Performance.PercentMemoryAvailable.DS" Accessibility="Internal" Batching="false"> <Configuration> <xsd:element minOccurs="1" type="xsd:string" name="ComputerName" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element minOccurs="1" type="xsd:integer" name="IntervalSeconds" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element minOccurs="1" type="xsd:double" name="ScaleBy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> </Configuration> <OverrideableParameters> <OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int" /> </OverrideableParameters> <ModuleImplementation Isolation="Any"> <Composite> <MemberModules> <DataSource ID="DS" TypeID="Perf!System.Performance.OptimizedDataProvider"> <ComputerName>$Config/ComputerName$</ComputerName> <CounterName>Available KBytes</CounterName> <ObjectName>Memory</ObjectName> <InstanceName /> <AllInstances>false</AllInstances> <Frequency>$Config/IntervalSeconds$</Frequency> <ScaleBy>$Config/ScaleBy$</ScaleBy> <Tolerance>0</Tolerance> <ToleranceType>Absolute</ToleranceType> <MaximumSampleSeparation>1</MaximumSampleSeparation> </DataSource> <ConditionDetection ID="ComputePercentage" TypeID="System!System.Computation"> <NumericValue> <Product> <NumericValue> <XPathQuery Type="Double">Value</XPathQuery> </NumericValue> <NumericValue> <Value>100</Value> </NumericValue> </Product> </NumericValue> </ConditionDetection> <ConditionDetection ID="CDPerfMapper" TypeID="Perf!System.Performance.DataGenericMapper"> <ObjectName>Memory</ObjectName> <CounterName>Percent Memory Available</CounterName> <InstanceName /> <Value>$Data/Value$</Value> </ConditionDetection> </MemberModules> <Composition> <Node ID="CDPerfMapper"> <Node ID="ComputePercentage"> <Node ID="DS" /> </Node> </Node> </Composition> </Composite> </ModuleImplementation> <OutputType>Perf!System.Performance.Data</OutputType> </DataSourceModuleType>
I am going to publish my complete example Management Pack in full here: