Category Archives: Authoring

Computer and Instance Group Fragments in VSAE

I’m updating my Technet posts about creating groups in the R2 Authoring Console. Here are the same examples using the Visual Studio Authoring Extensions. You can add these as templates to your fragment library for use in future development projects.

 

How to create a computer group using VSAE

 

Original post: How to create a computer group in the R2 Authoring Console

 

The main thing to focus on here is $MPElement[Name="YourMp.Class.YourClass"]$. This is referencing the class in which you want to include it’s hosting Windows Computer object.

 

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        <ClassType ID="YourMp.Class.YourComputerGroup" Abstract="false" Accessibility="Public" Base="SC!Microsoft.SystemCenter.ComputerGroup" Hosted="false" Singleton="true" />
      </ClassTypes>
    </EntityTypes>
  </TypeDefinitions>
  <Monitoring>
    <Discoveries>
      <Discovery ID="YourMp.Discovery.YourComputerGroup" ConfirmDelivery="false" Enabled="true" Priority="Normal" Remotable="true" Target="YourMp.Class.YourComputerGroup">
        <Category>Discovery</Category>
        <DiscoveryTypes />
        <DataSource ID="DS1" TypeID="SC!Microsoft.SystemCenter.GroupPopulator">
          <RuleId>$MPElement$</RuleId>
          <GroupInstanceId>$MPElement[Name="YourMp.Class.YourComputerGroup"]$</GroupInstanceId>
          <MembershipRules>
            <MembershipRule>
              <MonitoringClass>$MPElement[Name="Windows!Microsoft.Windows.Computer"]$</MonitoringClass>
              <RelationshipClass>$MPElement[Name="SC!Microsoft.SystemCenter.ComputerGroupContainsComputer"]$</RelationshipClass>
              <Expression>
                <Contains>
                  <MonitoringClass>$MPElement[Name="YourMp.Class.YourClass"]$</MonitoringClass>
                </Contains>
              </Expression>
            </MembershipRule>
          </MembershipRules>
        </DataSource>
      </Discovery>
    </Discoveries>
  </Monitoring>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="YourMp.Class.YourComputerGroup">
          <Name>Your Computer Group</Name>
          <Description>This group contains instances of Windows Computer objects that host YourClass.</Description>
        </DisplayString>
        <DisplayString ElementID="YourMp.Discovery.YourComputerGroup">
          <Name>Your Group Discovery</Name>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

 

How to create an instance group using VSAE

 

Original post: How to create an instance group in the R2 Authoring Console

 

The main thing to focus on here is $MPElement[Name="YourMp.Class.YourFirstClass"]$. This is referencing the discovered instances in which you want to include in your group. You can add multiple classes if you need the group to contain different types of instances.

 

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        <ClassType ID="YourMp.Class.YourInstanceGroup" Abstract="false" Accessibility="Public" Base="MSIL!Microsoft.SystemCenter.InstanceGroup" Hosted="false" Singleton="true" />
      </ClassTypes>
    </EntityTypes>
  </TypeDefinitions>
  <Monitoring>
    <Discoveries>
      <Discovery ID="YourMp.Discovery.YourInstanceGroup" ConfirmDelivery="false" Enabled="true" Priority="Normal" Remotable="true" Target="YourMp.Class.YourInstanceGroup">
        <Category>Discovery</Category>
        <DiscoveryTypes>
          <DiscoveryClass TypeID="YourMp.Class.YourFirstClass" />
          <DiscoveryClass TypeID="YourMp.Class.YourSecondClass" />
        </DiscoveryTypes>
        <DataSource ID="DS1" TypeID="SC!Microsoft.SystemCenter.GroupPopulator">
          <RuleId>$MPElement$</RuleId>
          <GroupInstanceId>$MPElement[Name="YourMp.Class.YourInstanceGroup"]$</GroupInstanceId>
          <MembershipRules>
            <MembershipRule>
              <MonitoringClass>$MPElement[Name="YourMp.Class.YourFirstClass"]$</MonitoringClass>
              <RelationshipClass>$MPElement[Name="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$</RelationshipClass>
            </MembershipRule>
            <MembershipRule>
              <MonitoringClass>$MPElement[Name="YourMp.Class.YourSecondClass"]$</MonitoringClass>
              <RelationshipClass>$MPElement[Name="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$</RelationshipClass>
            </MembershipRule>
          </MembershipRules>
        </DataSource>
      </Discovery>
    </Discoveries>
  </Monitoring>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="YourMp.Class.YourInstanceGroup">
          <Name>Your Instances Group</Name>
          <Description>This group contains all discovered instances referenced in the MonitoringClass(es).</Description>
        </DisplayString>
        <DisplayString ElementID="YourMp.Discovery.YourInstanceGroup">
          <Name>Your Instance Group Discovery</Name>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

 

How to create a group of Windows Computer instances that host some class and matches a property of that class.

 

Original post: How to create a group of Windows Computers based on a discovered property of virtually any class

 

The main thing to focus on here is $MPElement[Name="YourMp.Class.SomeClass"]$. This is referencing the Windows Computer hosted instances in which you want to include in your group. Also notice SomeProperty and SomePattern – this is the property you will be comparing in your regular expression.

 

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        <ClassType ID="YourMp.Class.YourComputerGroup" Abstract="false" Accessibility="Public" Base="SC!Microsoft.SystemCenter.ComputerGroup" Hosted="false" Singleton="true" />
      </ClassTypes>
    </EntityTypes>
  </TypeDefinitions>
  <Monitoring>
    <Discoveries>
      <Discovery ID="YourMp.Discovery.YourComputerGroup" ConfirmDelivery="false" Enabled="true" Priority="Normal" Remotable="true" Target="YourMp.Class.YourComputerGroup">
        <Category>Discovery</Category>
        <DiscoveryTypes />
        <DataSource ID="DS1" TypeID="SC!Microsoft.SystemCenter.GroupPopulator">
          <RuleId>$MPElement$</RuleId>
          <GroupInstanceId>$MPElement[Name="YourMp.Class.YourComputerGroup"]$</GroupInstanceId>
          <MembershipRules>
            <MembershipRule>
              <MonitoringClass>$MPElement[Name="Windows!Microsoft.Windows.Computer"]$</MonitoringClass>
              <RelationshipClass>$MPElement[Name="SC!Microsoft.SystemCenter.ComputerGroupContainsComputer"]$</RelationshipClass>
              <Expression>
                <Contains>
                  <MonitoringClass>$MPElement[Name="SomeMp.Class.SomeClass"]$</MonitoringClass>
                  <Expression>
                    <RegExExpression>
                      <ValueExpression>
                        <Property>$MPElement[Name="SomeMp.Class.SomeClass"]/SomeProperty$</Property>
                      </ValueExpression>
                      <Operator>MatchesRegularExpression</Operator>
                      <Pattern>SomePattern</Pattern>
                    </RegExExpression>
                  </Expression>
                </Contains>
              </Expression>
            </MembershipRule>
          </MembershipRules>
        </DataSource>
      </Discovery>
    </Discoveries>
  </Monitoring>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="YourMp.Class.YourComputerGroup">
          <Name>Your Computer Group</Name>
          <Description>This group contains Windows Computer instances that host some class and matches some property of that class.</Description>
        </DisplayString>
        <DisplayString ElementID="YourMp.Discovery.YourComputerGroup">
          <Name>Your Group Discovery</Name>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

 

Check out this other post about adding Health Service objects to a group.

 

Need help developing a management pack? Drop us a line

SCOMskills_Signature.

 

 

_

Dependency Monitor

If you’ve been following the series, you should have two classes and a unit monitor. As discussed earlier in the series, the base class types used are Local Application and Application Component, and these do not automatically rollup health to its hosting class.

If you want unit monitors targeting the application component class to rollup health to its hosting class (local application), you can add a dependency monitor

I prefer to add dependency monitors to the fragment that contains the class in which I want to rollup. So, this fragment is a repeat of the application component class fragment posted earlier, with the exception of including the dependency monitor.

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<TypeDefinitions>
<EntityTypes>
<ClassTypes>
<ClassType ID="SCOMskills.Demo.ApplicationComponent.Class" Abstract="false" Accessibility="Public" Base="Windows!Microsoft.Windows.ApplicationComponent" Hosted="true" Singleton="false">
<Property ID="CsvField1" Key="false" Type="string"/>
<Property ID="CsvField2" Key="false" Type="string"/>
</ClassType>
</ClassTypes>
<RelationshipTypes>
<RelationshipType ID="LocalApplicationHostsApplicationComponent" Base="System!System.Hosting" Accessibility="Public">
<Source ID="LocalApplication" Type="SCOMskills.Demo.LocalApplication.Class"/>
<Target ID="ApplicationComponent" Type="SCOMskills.Demo.ApplicationComponent.Class"/>
</RelationshipType>
</RelationshipTypes>
</EntityTypes>
</TypeDefinitions>
<Monitoring>
<Monitors>
<DependencyMonitor ID="ApplicationComponentAvailabilityRollup" Accessibility=“InternalEnabled=“trueMemberMonitor=“Health!System.Health.AvailabilityStateParentMonitorID=“Health!System.Health.AvailabilityStateRelationshipType=“LocalApplicationHostsApplicationComponentPriority=“NormalRemotable=“falseTarget=“SCOMskills.Demo.LocalApplication.Class>
<Category>AvailabilityHealth</Category>
<Algorithm>WorstOf</Algorithm>
</DependencyMonitor>
</Monitors>
</Monitoring>
<LanguagePacks>
<LanguagePack ID="ENU" IsDefault="true">
<DisplayStrings>
<DisplayString ElementID="SCOMskills.Demo.ApplicationComponent.Class">
<Name>SCOMskills Application Component Class</Name>
</DisplayString>
<DisplayString ElementID="SCOMskills.Demo.ApplicationComponent.Class" SubElementID="CsvField1">
<Name>CSV Field 1</Name>
</DisplayString>
<DisplayString ElementID="SCOMskills.Demo.ApplicationComponent.Class" SubElementID="CsvField2">
<Name>CSV Field 2</Name>
</DisplayString>
<DisplayString ElementID="LocalApplicationHostsApplicationComponent">
<Name>Local Application class hosts Application Component class</Name>
</DisplayString>
<DisplayString ElementID="ApplicationComponentAvailabilityRollup">
<Name>Application Component Health</Name>
</DisplayString>
</DisplayStrings>
</LanguagePack>
</LanguagePacks>
</ManagementPackFragment>

Two-State Event Detection

This fragment demonstrates how you can use one of the built-in, two-state Windows event modules to compose a unit monitor. This fragment is the next example in the VSAE Fragment category; the xml fragment below should work as described if you have been following the series.

Module Type used in this post: Microsoft.Windows.2SingleEventLog2StateMonitorType

Scenario

Change state to critical and raise a critical alert when event Id 101, from  source TEST, and event level is Error is detected in the Application log. Resolve alert when same event is detected with event level Information.

A note about event level:

1 = Error

4 = Information

 

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Monitoring>
    <Monitors>
      <UnitMonitor ID="SCOMskills.Demo.Event101.2State" Accessibility="Public" ConfirmDelivery="false" Enabled="true" ParentMonitorID="Health!System.Health.AvailabilityState" Priority="Normal" Remotable="false" Target="SCOMskills.Demo.ApplicationComponent.Class" TypeID="Windows!Microsoft.Windows.2SingleEventLog2StateMonitorType">
        <Category>AvailabilityHealth</Category>
        <AlertSettings AlertMessage="SCOMskills.Demo.Event101.2State.AlertMessage">
          <AlertOnState>Error</AlertOnState>
          <AutoResolve>true</AutoResolve>
          <AlertPriority>Normal</AlertPriority>
          <AlertSeverity>Error</AlertSeverity>
          <AlertParameters>
            <AlertParameter1>$Data/Context/EventDescription$</AlertParameter1>
          </AlertParameters>
        </AlertSettings>
        <OperationalStates>
          <OperationalState ID="Unhealthy" HealthState="Error" MonitorTypeStateID="FirstEventRaised"/>
          <OperationalState ID="Healthy" HealthState="Success" MonitorTypeStateID="SecondEventRaised"/>
        </OperationalStates>
        <Configuration>
          <FirstComputerName>$Target/Host/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$</FirstComputerName>
          <FirstLogName>Application</FirstLogName>
          <FirstExpression>
            <And>
              <Expression>
                <SimpleExpression>
                  <ValueExpression>
                    <XPathQuery>EventSourceName</XPathQuery>
                  </ValueExpression>
                  <Operator>Equal</Operator>
                  <ValueExpression>
                    <Value>TEST</Value>
                  </ValueExpression>
                </SimpleExpression>
              </Expression>
              <Expression>
                <SimpleExpression>
                  <ValueExpression>
                    <XPathQuery>EventDisplayNumber</XPathQuery>
                  </ValueExpression>
                  <Operator>Equal</Operator>
                  <ValueExpression>
                    <Value>101</Value>
                  </ValueExpression>
                </SimpleExpression>
              </Expression>
              <Expression>
                <SimpleExpression>
                  <ValueExpression>
                    <XPathQuery>EventLevel</XPathQuery>
                  </ValueExpression>
                  <Operator>Equal</Operator>
                  <ValueExpression>
                    <Value>1</Value>
                  </ValueExpression>
                </SimpleExpression>
              </Expression>
            </And>
          </FirstExpression>
          <SecondComputerName>$Target/Host/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$</SecondComputerName>
          <SecondLogName>Application</SecondLogName>
          <SecondExpression>
            <And>
              <Expression>
                <SimpleExpression>
                  <ValueExpression>
                    <XPathQuery>EventSourceName</XPathQuery>
                  </ValueExpression>
                  <Operator>Equal</Operator>
                  <ValueExpression>
                    <Value>TEST</Value>
                  </ValueExpression>
                </SimpleExpression>
              </Expression>
              <Expression>
                <SimpleExpression>
                  <ValueExpression>
                    <XPathQuery>EventDisplayNumber</XPathQuery>
                  </ValueExpression>
                  <Operator>Equal</Operator>
                  <ValueExpression>
                    <Value>101</Value>
                  </ValueExpression>
                </SimpleExpression>
              </Expression>
              <Expression>
                <SimpleExpression>
                  <ValueExpression>
                    <XPathQuery>EventLevel</XPathQuery>
                  </ValueExpression>
                  <Operator>Equal</Operator>
                  <ValueExpression>
                    <Value>4</Value>
                  </ValueExpression>
                </SimpleExpression>
              </Expression>
            </And>
          </SecondExpression>
        </Configuration>
      </UnitMonitor>
    </Monitors>
  </Monitoring>
  <Presentation>
    <StringResources>
      <StringResource ID="SCOMskills.Demo.Event101.2State.AlertMessage"/>
    </StringResources>
  </Presentation>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="SCOMskills.Demo.Event101.2State">
          <Name>Event 101 Monitor</Name>
          <Description>Detect event Id 101. Raise alert if error, resolve alert if informational.</Description>
        </DisplayString>
        <DisplayString ElementID="SCOMskills.Demo.Event101.2State.AlertMessage">
          <Name>Detected Event Id 101</Name>
          <Description>{0}</Description>
        </DisplayString>
        <DisplayString ElementID="SCOMskills.Demo.Event101.2State" SubElementID="Healthy">
          <Name>Healthy</Name>
        </DisplayString>
        <DisplayString ElementID="SCOMskills.Demo.Event101.2State" SubElementID="Unhealthy">
          <Name>Unhealthy</Name>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

 
 
Logo_Main_LinkedIn[4]

_

Timed Script Discovery (vbscript part 2)

Referring back to the previous VSAE Fragment post regarding the Windows Timed Script Discovery Provider, you can see this module can be implemented directly in a new discovery. In most cases, this works very well. In some cases, you may want to create a custom discovery provider in order to expose configuration elements as separate parameters – particularly override parameters.

Example of override parameters by implementing the built-in module type in your discovery

image

Zooming in on the script arguments, you can see this:

$MPElement$ $Target/Id$ $Target/Host/Property[Type=”Windows!Microsoft.Windows.Computer”]/PrincipalName$ c:\ScomSkillsDemo.csv

This isn’t very friendly to an operator that is setting a discovery override, and presents greater opportunity for override mistakes. The only parameter an operator might need to change is the CSV File Location.

So, how can this be improved from an operator perspective? One option is to create a new module type. If you have multiple parameters you want separated in the Operations console, this is probably the best option, as the built-in provider only allows for a single string of arguments.

This example is purely to offer a better experience for the operator creating overrides – there is really no difference in how instances will be discovered under the hood. The result will be new override parameters available in the Operations console.

Example of override parameters by implementing a custom discovery provider

image

 

What does this do?

This performs the same discovery as the previous fragment, but creates custom override parameters in the Operations console.

 

Fragment 1: Custom discovery module type

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TypeDefinitions>
    <ModuleTypes>
      <DataSourceModuleType ID="SCOMskills.Demo.TimedScript.DiscoveryProvider.Custom" Accessibility="Public">
        <Configuration>
          <xsd:element minOccurs="1" name="Interval" type="xsd:integer" />
          <xsd:element minOccurs="1" name="CsvFileLocation" type="xsd:string" />
          <xsd:element minOccurs="1" name="PrincipalName" type="xsd:string" />
          <xsd:element minOccurs="1" name="Timeout" type="xsd:integer" />
        </Configuration>
        <OverrideableParameters>
          <OverrideableParameter ID="Interval" ParameterType="int" Selector="$Config/Interval$"/>
          <OverrideableParameter ID="CsvFileLocation" ParameterType="string" Selector="$Config/CsvFileLocation$"/>
          <OverrideableParameter ID="Timeout" ParameterType="int" Selector="$Config/Timeout$"/>
        </OverrideableParameters>
        <ModuleImplementation Isolation="Any">
          <Composite>
            <MemberModules>
              <DataSource ID="Scheduler" TypeID="System!System.Scheduler">
                <Scheduler>
                  <SimpleReccuringSchedule>
                    <Interval>$Config/Interval$</Interval>
                  </SimpleReccuringSchedule>
                  <ExcludeDates />
                </Scheduler>
              </DataSource>
              <ProbeAction ID="Script" TypeID="Windows!Microsoft.Windows.ScriptDiscoveryProbe">
                <ScriptName>SCOMskills.Demo.Discovery.vbs</ScriptName>
                <Arguments>$MPElement$ $Target/Id$ $Config/PrincipalName$ $Config/CsvFileLocation$</Arguments>
                <ScriptBody>
                  <![CDATA[
Option Explicit

Dim oArgs
Set oArgs = WScript.Arguments
if oArgs.Count < 4 Then
   Wscript.Quit -1
End If

Dim SourceID, ManagedEntityId, TargetComputer, SourceFile

SourceId = oArgs(0)
ManagedEntityId = oArgs(1)
TargetComputer = oArgs(2)
SourceFile = oArgs(3)

Dim oAPI, oDiscoveryData, oInst
Set oAPI = CreateObject("MOM.ScriptAPI")
set oDiscoveryData = oAPI.CreateDiscoveryData(0, SourceId, ManagedEntityId)

Dim oFso, oFile, aField
Set oFso = CreateObject("Scripting.FileSystemObject")

If (oFso.FileExists(SourceFile)) Then
Set oFile = oFso.OpenTextFile(SourceFile)
aField = split(oFile.ReadLine,",")

set oInst = oDiscoveryData.CreateClassInstance("$MPElement[Name='SCOMskills.Demo.ApplicationComponent.Class']$")
call oInst.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", TargetComputer)
call oInst.AddProperty("$MPElement[Name='SCOMskills.Demo.ApplicationComponent.Class']/CsvField1$", aField(0))
call oInst.AddProperty("$MPElement[Name='SCOMskills.Demo.ApplicationComponent.Class']/CsvField2$", aField(1))
call oInst.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", TargetComputer)
call oDiscoveryData.AddInstance(oInst)

Else

Wscript.Quit -1

End If

Call oAPI.Return(oDiscoveryData) 
                ]]>
                </ScriptBody>
                <TimeoutSeconds>$Config/Timeout$</TimeoutSeconds>
              </ProbeAction>
            </MemberModules>
            <Composition>
              <Node ID="Script">
                <Node ID="Scheduler" />
              </Node>
            </Composition>
          </Composite>
        </ModuleImplementation>
        <OutputType>System!System.Discovery.Data</OutputType>
      </DataSourceModuleType>
    </ModuleTypes>
  </TypeDefinitions>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="SCOMskills.Demo.TimedScript.DiscoveryProvider.Custom">
          <Name>SCOMskills Custom Timed Script Discovery</Name>
        </DisplayString>
        <DisplayString ElementID="SCOMskills.Demo.TimedScript.DiscoveryProvider.Custom" SubElementID="CsvFileLocation">
          <Name>CSV File Location</Name>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

Fragment 2: Implementing the custom discovery module

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Monitoring>
    <Discoveries>
      <Discovery ID="SCOMskills.Demo.TimedScript.Custom.Discovery" ConfirmDelivery="false" Enabled="true" Priority="Normal" Remotable="true" Target="SCOMskills.Demo.LocalApplication.Class">
        <Category>Discovery</Category>
        <DiscoveryTypes>
          <DiscoveryClass TypeID="SCOMskills.Demo.ApplicationComponent.Class">
            <Property TypeID="SCOMskills.Demo.ApplicationComponent.Class" PropertyID="CsvField1"/>
            <Property TypeID="SCOMskills.Demo.ApplicationComponent.Class" PropertyID="CsvField2"/>
            <Property TypeID="System!System.Entity" PropertyID="DisplayName"/>
          </DiscoveryClass>
        </DiscoveryTypes>
        <DataSource ID="DS" TypeID="SCOMskills.Demo.TimedScript.DiscoveryProvider.Custom">
          <Interval>60</Interval>
          <CsvFileLocation>c:\ScomSkillsDemo.csv</CsvFileLocation>
          <PrincipalName>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</PrincipalName>
          <Timeout>60</Timeout>
        </DataSource>
      </Discovery>
    </Discoveries>
  </Monitoring>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="SCOMskills.Demo.TimedScript.Custom.Discovery">
          <Name>SCOMskills Timed Script Custom Discovery</Name>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>
 
 
 
 
Logo_Main_LinkedIn

_

Logical Disk Free Space monitor doesn’t cookdown

I haven’t looked at the internals of this monitor in a long time. But recently I was working on a modified disk free space monitoring solution for a customer, and to my surprise uncovered the fact that the built-in logical disk space monitor in the Windows management packs do not utilize cookdown. This had changed at some point in time, because I know these monitors  took advantage of cookdown in previous versions.

Fixing this wasn’t officially a part of the disk monitoring project I was tasked with, but just knowing the fact it didn’t utilize cookdown was enough to compel me to rewrite the entire workflow. After I fixed the cookdown problem and finished other additions to the disk space monitor, I was going to post a management pack here with an updated logical disk free space monitor…until I stumbled across a blog entry Kevin Holman posted over a year ago.

I’m not sure if Kevin realized at the time that his addendum MP fixed the cookdown problem, but it does. Hot smile Head over to his blog to download the addendum MP, especially if your company uses a lot of instance level disk space overrides.

 

For those that need a refresher on cookdown, this is a programming technique that (if implemented properly) will execute only one instance of a script data source even if there are multiple monitoring instances that consume the output. The key to cookdown is passing no (or only necessary) configuration elements into the script execution, and processing instance and state filtering after script execution by using expression filters.

If the script expects configuration input, and the monitor configuration is changed by an override, the script will need to run once for each instance override. In the case of the logical disk free space monitor, this leaves a huge door of opportunity to run multiple copies of the data source script, and this will lead to resource consumption on the monitored computer.

 

The built-in logical disk free space data source module (cookdown broken with overrides)

 

<DataSourceModuleType ID="Microsoft.Windows.Server.2008.FreeSpace.Moduletype" Accessibility="Internal" Batching="false">
  <Configuration>
    <xsd:element minOccurs="1" name="ComputerName" type="xsd:string" />
    <xsd:element minOccurs="1" name="DiskLabel" type="xsd:string" />
    <xsd:element minOccurs="1" name="IntervalSeconds" type="xsd:integer" />
    <xsd:element minOccurs="1" name="SystemDriveWarningMBytesThreshold" type="xsd:double" />
    <xsd:element minOccurs="1" name="SystemDriveWarningPercentThreshold" type="xsd:double" />
    <xsd:element minOccurs="1" name="SystemDriveErrorMBytesThreshold" type="xsd:double" />
    <xsd:element minOccurs="1" name="SystemDriveErrorPercentThreshold" type="xsd:double" />
    <xsd:element minOccurs="1" name="NonSystemDriveWarningMBytesThreshold" type="xsd:double" />
    <xsd:element minOccurs="1" name="NonSystemDriveWarningPercentThreshold" type="xsd:double" />
    <xsd:element minOccurs="1" name="NonSystemDriveErrorMBytesThreshold" type="xsd:double" />
    <xsd:element minOccurs="1" name="NonSystemDriveErrorPercentThreshold" type="xsd:double" />
  </Configuration>
  <OverrideableParameters>
    <OverrideableParameter ID="Interval" Selector="$Config/IntervalSeconds$" ParameterType="int" />
    <OverrideableParameter ID="SystemDriveWarningMBytesThreshold" Selector="$Config/SystemDriveWarningMBytesThreshold$" ParameterType="double" />
    <OverrideableParameter ID="SystemDriveWarningPercentThreshold" Selector="$Config/SystemDriveWarningPercentThreshold$" ParameterType="double" />
    <OverrideableParameter ID="SystemDriveErrorMBytesThreshold" Selector="$Config/SystemDriveErrorMBytesThreshold$" ParameterType="double" />
    <OverrideableParameter ID="SystemDriveErrorPercentThreshold" Selector="$Config/SystemDriveErrorPercentThreshold$" ParameterType="double" />
    <OverrideableParameter ID="NonSystemDriveWarningMBytesThreshold" Selector="$Config/NonSystemDriveWarningMBytesThreshold$" ParameterType="double" />
    <OverrideableParameter ID="NonSystemDriveWarningPercentThreshold" Selector="$Config/NonSystemDriveWarningPercentThreshold$" ParameterType="double" />
    <OverrideableParameter ID="NonSystemDriveErrorMBytesThreshold" Selector="$Config/NonSystemDriveErrorMBytesThreshold$" ParameterType="double" />
    <OverrideableParameter ID="NonSystemDriveErrorPercentThreshold" Selector="$Config/NonSystemDriveErrorPercentThreshold$" ParameterType="double" />
  </OverrideableParameters>

 

The proper way to implement a script data source to utilize cookdown (configuration and state filtering should happen at the monitor type, not the data source module)

 

<DataSourceModuleType ID="Microsoft.Windows.Server.2008.Monitoring.Addendum.FreeSpace.ModuleType" Accessibility="Internal" Batching="false">
  <Configuration>
    <xsd:element minOccurs="1" name="IntervalSeconds" type="xsd:int" />
    <xsd:element minOccurs="1" name="TargetComputerName" type="xsd:string" />
  </Configuration>

 

I wonder if Microsoft will plan to fix this in the future. Good thing these modules are flagged internal, so it shouldn’t be much to ask and an update wouldn’t break upgrade compatibility for customers.

This post applies to Windows MP versions 6.0.6958 – 6.0.6989.0.

_