All posts by Jonathan Almquist

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>

Filtered Registry Discovery Provider

AKA: Microsoft.Windows.FilteredRegistryDiscoveryProvider

This is the third post in the new VSAE Fragment category. The provider is used to discover a class type and its properties by reading keys and values from the Windows registry.

What does it do?

This particular fragment can be used to discover the class type discuss here. It demonstrates how to discover different types of properties: Integer, String, and Double (or decimal).

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Monitoring>
<Discoveries>
<Discovery ID="SCOMskills.Demo.FilteredRegistry.Discovery" Target="Windows!Microsoft.Windows.Computer" Remotable="true" Enabled="true">
<Category>Discovery</Category>
<DiscoveryTypes>
<DiscoveryClass TypeID="SCOMskills.Demo.FilteredRegistry.Class">
<Property PropertyID="IntegerProperty"/>
<Property PropertyID="StringProperty"/>
<Property PropertyID="DoubleProperty"/>
<Property TypeID="System!System.Entity" PropertyID="DisplayName"/>
</DiscoveryClass>
</DiscoveryTypes>
<DataSource ID="DS" TypeID="Windows!Microsoft.Windows.FilteredRegistryDiscoveryProvider">
<ComputerName>$Target/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$</ComputerName>
<RegistryAttributeDefinitions>
<!--===============================================================================-->
<!--Define registry keys, values, and types. -->
<!--Path and attribute types: http://msdn.microsoft.com/en-us/library/jj130492.aspx-->
<!--===============================================================================-->
<RegistryAttributeDefinition>
<AttributeName>SCOMskillsKeyExists</AttributeName>
<Path>SOFTWARE\SCOMskills</Path>
<PathType>0</PathType>
<AttributeType>0</AttributeType>
</RegistryAttributeDefinition>
<RegistryAttributeDefinition>
<AttributeName>IntegerValue</AttributeName>
<Path>SOFTWARE\SCOMskills\Integer</Path>
<PathType>1</PathType>
<!--reg_dword, any integer value-->
<AttributeType>2</AttributeType>
</RegistryAttributeDefinition>
<RegistryAttributeDefinition>
<AttributeName>StringValue</AttributeName>
<Path>SOFTWARE\SCOMskills\String</Path>
<PathType>1</PathType>
<!--reg string-->
<AttributeType>1</AttributeType>
</RegistryAttributeDefinition>
<RegistryAttributeDefinition>
<AttributeName>DoubleValue</AttributeName>
<Path>SOFTWARE\SCOMskills\Double</Path>
<PathType>1</PathType>
<!--reg string, value can be a double or integer-->
<AttributeType>3</AttributeType>
</RegistryAttributeDefinition>
</RegistryAttributeDefinitions>
<Frequency>60</Frequency>
<ClassId>$MPElement[Name="SCOMskills.Demo.FilteredRegistry.Class"]$</ClassId>
<!--========================================-->
<!--Map registry filters to class properties-->
<!--========================================-->
<InstanceSettings>
<Settings>
<Setting>
<Name>$MPElement[Name="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Name>
<Value>$Target/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="SCOMskills.Demo.FilteredRegistry.Class"]/IntegerProperty$</Name>
<Value>$Data/Values/IntegerValue$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="SCOMskills.Demo.FilteredRegistry.Class"]/StringProperty$</Name>
<Value>$Data/Values/StringValue$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="SCOMskills.Demo.FilteredRegistry.Class"]/DoubleProperty$</Name>
<Value>$Data/Values/DoubleValue$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="System!System.Entity"]/DisplayName$</Name>
<Value>$Target/Property[Type="Windows!Microsoft.Windows.Computer"]/NetbiosComputerName$</Value>
</Setting>
</Settings>
</InstanceSettings>
<!--=========================================================-->
<!--Discover class instance if SCOMskills registry key exists-->
<!--=========================================================-->
<Expression>
<SimpleExpression>
<ValueExpression>
<XPathQuery Type="Boolean">Values/SCOMskillsKeyExists</XPathQuery>
</ValueExpression>
<Operator>Equal</Operator>
<ValueExpression>
<Value Type="Boolean">true</Value>
</ValueExpression>
</SimpleExpression>
</Expression>
</DataSource>
</Discovery>
</Discoveries>
</Monitoring>
<LanguagePacks>
<LanguagePack ID="ENU" IsDefault="true">
<!--============================================================-->
<!--Provide friendly display names for elements in this fragment-->
<!--============================================================-->
<DisplayStrings>
<DisplayString ElementID="SCOMskills.Demo.FilteredRegistry.Discovery">
<Name>Filtered registry class discovery.</Name>
</DisplayString>
<DisplayString ElementID="SCOMskills.Demo.FilteredRegistry.Discovery" SubElementID="DS">
<Name>Filtered registry discovery data source</Name>
</DisplayString>
</DisplayStrings>
</LanguagePack>
</LanguagePacks>
</ManagementPackFragment>

Microsoft Windows Local Application class type

AKA: Microsoft.Windows.LocalApplication

This is the second post in the new VSAE Fragment category. The purpose of these types of posts is to provide a practical demonstration of how to create your own fragment library. I find this useful in management pack authoring, because it’s much easier to add and modify an existing fragment than to create elements and modules from scratch each time.

What does it do?

This may be the most common base classes used for a seed class. It’s easy to implement, because it doesn’t require you to create a hosting relationships. This base class *will* rollup to the windows computer class, as a local application. So, do not choose this as a base if you do not want your application to rollup to windows computer! This is considered a concrete class, and rolls up to windows computer.

Go here for a fragment that will discover this class type using the filtered registry discovery module.

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<TypeDefinitions>
<EntityTypes>
<ClassTypes>
<!--=======================================-->
<!--Define application class and properties-->
<!--=======================================-->
<ClassType ID="SCOMskills.Demo.FilteredRegistry.Class" Abstract="false" Accessibility="Public" Base="Windows!Microsoft.Windows.LocalApplication" Hosted="true" Singleton="false">
<Property ID="IntegerProperty" Key="false" Type="int" />
<Property ID="StringProperty" Key="false" Type="string" />
<Property ID="DoubleProperty" Key="false" Type="double" />
</ClassType>
</ClassTypes>
</EntityTypes>
</TypeDefinitions>
<LanguagePacks>
<LanguagePack ID="ENU" IsDefault="true">
<!--============================================================-->
<!--Provide friendly display names for elements in this fragment-->
<!--============================================================-->
<DisplayStrings>
<DisplayString ElementID="SCOMskills.Demo.FilteredRegistry.Class">
<Name>SCOMskills Demo Filtered Registry Class</Name>
<Description>Demonstration of Microsoft.Windows.FilteredRegistryDiscoveryProvider</Description>
</DisplayString>
<DisplayString ElementID="SCOMskills.Demo.FilteredRegistry.Class" SubElementID="IntegerProperty">
<Name>Integer Property</Name>
</DisplayString>
<DisplayString ElementID="SCOMskills.Demo.FilteredRegistry.Class" SubElementID="StringProperty">
<Name>String Property</Name>
</DisplayString>
<DisplayString ElementID="SCOMskills.Demo.FilteredRegistry.Class" SubElementID="DoubleProperty">
<Name>Double Property</Name>
</DisplayString>
</DisplayStrings>
</LanguagePack>
</LanguagePacks>
</ManagementPackFragment>

Visual Studio Authoring Extensions – Fragments, fragments, fragments!

All management pack authoring I do is by using fragments. In my opinion, fragments are the most flexible authoring element in the VSAE, as they offer full visibility into the XML code and the ability to create a library of useful fragments that can later be reused in other management packs.

I’m kicking off a new blog category named VSAE Fragment. The purpose of these types of posts is to give practical examples of using modules that are defined in OpsMgr management pack libraries, as well as how to piece together custom modules for composite workflows. MSDN already has a library of module examples here, but sometimes I find myself searching to fill in some blanks. Hopefully this will help others as much as they help me.

I’m starting the VSAE Fragment category by providing the most basic, and essential fragment I use in every new management pack: the mp.DisplayName fragment.

What does it do?

Provides a friendly management pack display name and description in the Operations console.

 

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="SCOMskills.Demo">
          <Name>SCOMskills Demo</Name>
          <Description>A demo management pack.</Description>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

Create a Group of Health Service Watcher Objects Using VSAE

Plenty of bloggers have written about creating groups of health service watcher objects. The purpose of these types of groups is primarily for notification subscriptions. The reason why we need to include Health Service Watcher objects in our subscription criteria is so recipients also receive notifications about Health Service Heartbeat Failures and Computer Not Reachable alerts.

In this post, I will demonstrate how to create these type of groups using the Visual Studio Authoring Extensions.

In this example, I will create a group of health service watcher objects based on membership of another group (the "source" group). How the source group was created does not matter, as our group of Health Service Watcher objects will always be dynamic in nature and match the source group membership.

Before you start, you’ll need to locate the sealed version of the MP that contains the source group. In this case, I’ll reference a built-in group in the Windows Operating System MP: Windows Server 2012 Computer Group. To figure out which MP the group is stored in, you can run the following command in the Operations Manager Command Shell (replace with your group name).

 Get-SCOMGroup -DisplayName 'Windows Server 2012 Computer Group' | Get-SCOMClass | Select ManagementPackName

 

In this example, the group is stored in the Microsoft.Windows.Server.Library.

1. Create a new Operations Manager 2012 Add-On project in Visual Studio, name it Demo.HealthServiceWatcherGroups, and add a reference to the Microsoft.Windows.Server.Library MP (or the MP containing your source group). Also add a reference to the Microsoft.SystemCenter.InstanceGroup.Library MP – you need to reference this for the discovery relationship.

NOTE: I use fragments heavily in MP authoring, and don’t rely on the templates at all. I think it offers much more flexibility and allows me to retain a library of my own fragments that I can reuse later. This MP will consist of three fragments; one for the MP display name, one for the singleton class (group), and one for the group discovery.

 

2. Add a new empty management pack fragment named mp.DisplayName.mpx, paste the following code into it, and save the fragment. This fragment will provide the MP friendly name.

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <
LanguagePacks>

    <
LanguagePack ID="ENU" IsDefault="true">

      <
DisplayStrings>

        <
DisplayString ElementID="Demo.HealthServiceWatcherGroups">

          <
Name>Demo – Health Service Watcher Groups</Name>

          <
Description>This management pack contains groups of Health Service Watcher objects.</Description>

        </
DisplayString>

      </
DisplayStrings>

    </
LanguagePack>

  </
LanguagePacks>

</
ManagementPackFragment>

3. Add a new empty management pack fragment named class.WindowsServer2012HswGroup.mpx, paste the follow code into it, and save the fragment. This fragment provides the group name and establishes the relationship type. Notice this is a singleton class, which is a group in this case. Also note that I am using default aliases that are generated by VSAE. I choose to use default aliases all the time, so I don’t get confused with custom aliases later. My preference is to store display strings in each  fragment, rather than bunching them all into a single fragment, but you might find other methods that work better for you.

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        <ClassType ID="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroup" Abstract="false" Accessibility="Public" Base="MSIL!Microsoft.SystemCenter.InstanceGroup" Hosted="false" Singleton="true" />
      </ClassTypes>
      <RelationshipTypes>
        <RelationshipType ID="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroupContainmentRelationship" Abstract="false" Accessibility="Public" Base="System!System.Containment">
          <Source ID="Demo.HealthServiceWatcherGroups.Source" Type="System!System.Group" />
          <Target ID="Demo.HealthServiceWatcherGroups.Entity" Type="System!System.Entity" />
        </RelationshipType>
      </RelationshipTypes>
    </EntityTypes>
  </TypeDefinitions>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroup">
          <Name>Demo - Windows Server 2012 Health Service Watcher Group</Name>
          <Description>Contains Health Service Watcher for all instances in the Windows Server 2012 group.</Description>
        </DisplayString>
        <DisplayString ElementID="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroupContainmentRelationship">
          <Name>Windows Server 2012 Health Service Watcher Containment Relationships</Name>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

 

4. Add a new empty management pack fragment named dis.WindowsServer2012HswGroup.mpx, paste the following code into it, and save the fragment. This fragment contains the actual discovery. The module performing the group population is specified in the data source. The main elements you need to be concerned with are highlighted; GroupInstanceId is the group (class) to be populated, MonitoringClass indicates what type of objects to populate the group with, and the expression indicates which source class (or group) to match. Also note MonitoringClass is AgentWatcher. This will populate the group with agents only, not other types of health service’s (like management servers or gateways).

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Monitoring>
    <Discoveries>
      <Discovery ID="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroup.Discovery" ConfirmDelivery="false" Enabled="true" Priority="Normal" Remotable="true" Target="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroup">
        <Category>Discovery</Category>
        <DiscoveryTypes>
          <DiscoveryRelationship TypeID="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities" />
        </DiscoveryTypes>
        <DataSource ID="GroupPop" TypeID="SC!Microsoft.SystemCenter.GroupPopulator">
          <RuleId>$MPElement$</RuleId>
          <GroupInstanceId>$MPElement[Name="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroup"]$</GroupInstanceId>
          <MembershipRules>
            <MembershipRule>
              <MonitoringClass>$MPElement[Name="SC!Microsoft.SystemCenter.AgentWatcher"]$</MonitoringClass>
              <RelationshipClass>$MPElement[Name="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroupContainmentRelationship"]$</RelationshipClass>
              <Expression>
                <Contains>
                  <MonitoringClass>$MPElement[Name="SC!Microsoft.SystemCenter.HealthService"]$</MonitoringClass>
                  <Expression>
                    <Contained>
                      <MonitoringClass>$MPElement[Name="MWSL!Microsoft.Windows.Server.6.2.ComputerGroup"]$</MonitoringClass>
                    </Contained>
                  </Expression>
                </Contains>
              </Expression>
            </MembershipRule>
          </MembershipRules>
        </DataSource>
      </Discovery>
    </Discoveries>
  </Monitoring>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroup.Discovery">
          <Name>Demo - Windows Server 2012 HSW Group Discovery</Name>
          <Description>Populates Demo - Windows Server 2012 HSW Group</Description>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

 

Sign, seal, and import the MP to see the end result.

 

Source group contains a mix of computer objects – both agents and management servers.

image

 

The new group contains health service watcher instances for agents running on Windows Server 2012.

image

 

I plan to post more on creating groups using the Visual Studio Authoring Extensions in the future, so check back or subscribe to the RSS feed.

If you are still using the R2 Authoring Console, I have those examples posted here.

How to create a computer group in the R2 Authoring Console
How to create an instance group in the R2 Authoring Console
How to create a group of Windows Computers based on a discovered property of virtually any class