Category Archives: VSAE Fragment

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

_

Timed Script Discovery (vbscript)

AKA: Microsoft.Windows.TimedScript.DiscoveryProvider

If you are following these VSAE Fragment posts in order, you’ll see they are tied together in the same example management pack. This fragment demonstrates the timed script discovery provider, and discovers the application component class discussed in the previous post.

What does it do?

This discovery uses a script to read a local csv file (c:\ScomSkills.csv). The file is expected to have two entries, separated by a comma. Doesn’t matter what the entries are, as they will simply be discovered as class properties.

One thing I’d like to callout here is the discovery of Entity\DisplayName, highlighted below. It is important to discover PrincipalName or NetbiosName for Entity\DisplayName, because this is what the source will be when monitors targeting this class generate an alert. Ever see an alert generated by "c:" or "Windows Server 2008"? Not very useful while looking at a long list of alerts in the console, and doesn’t help much if you have other processes that are expecting computer name values for source. This is also discussed here.

 

 

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Monitoring>
    <Discoveries>
      <Discovery ID="SCOMskills.Demo.TimedScript.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="Windows!Microsoft.Windows.TimedScript.DiscoveryProvider">
          <IntervalSeconds>60</IntervalSeconds>
          <SyncTime/>
          <ScriptName>SCOMskills.Demo.Discovery.vbs</ScriptName>
          <Arguments>$MPElement$ $Target/Id$ $Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$ c:\ScomSkillsDemo.csv</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>30</TimeoutSeconds>
        </DataSource>
      </Discovery>
    </Discoveries>
  </Monitoring>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="SCOMskills.Demo.TimedScript.Discovery">
          <Name>SCOMskills Timed Script Discovery</Name>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

Microsoft Windows Application Component class type

AKA: Microsoft.Windows.ApplicationComponent

Here is another post in the VSAE Fragment category, building on the Microsoft Windows Local Application class in the previous example. This is another common class type to use while authoring a custom management pack, as discuss here. Use this class to discover components hosted on your custom Local Application class. This could also be considered a type (or server role) of the hosting class.

What does it do?

Discovers a component (or type/role) that is hosted by the seed class discovered in the previous example. You will notice here the highlighted hosting relationship also needs to be discovered, since this isn’t automatically included in the Microsoft Windows Application Component class type.  Monitors targeting this class will not automatically rollup to the Windows computer, so long as you do not create a dependency or hosting relationship on local application. This class requires a relationship with it’s base class, which is typically the seed class. If the seed class is local application, then it will automatically rollup to windows computer, and in some cases this is not what you want. In many cases, you might want to target your base class, which would be targeting Windows operating system (more on that later – look at the best practices category).

<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>
<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>
</DisplayStrings>
</LanguagePack>
</LanguagePacks>
</ManagementPackFragment>