Menu Close

How to create a SCOM Group of Disks that are related to an Application using CONTAINED and CONTAINS

This is a very common request.  Perhaps you have an application that you discover and monitor, and the application owner wants specific overrides for the disks related to that application.  Initially, this seems really hard, because there is no direct relationship between an application on a server, and disks on a server.  However – there actually is.  The application is “hosted” (and therefore contained) by the Windows Computer object.  Disks are also hosted (and therefore contained) by the Windows Computer.  So we can use these two relationships in a group expression to get specific disks related to an application.

For instance:  You need a Group of (Logical Disk objects where the Drive Letter = C: ) but ONLY on Computers that contain an instance of your custom application?

 

Unfortunately, while this is such a simple thing to do – this cannot be done using the SCOM Console group authoring.  You need to drop down into XML and edit the group expression.  Here is an example.

In this example, I am discovering my custom application class:  (Demo.App.ServerRole.Class)

The XML is actually pretty simple.  The key here is using CONTAINS and CONTAINED.

My membership rule for the group says:

I want a group, of Logical Disks, where the Drive Letter = C: AND I only want disks that are CONTAINED by a Windows Computer object, where that Windows Computer object also CONTAINS an instance of my custom application class.

<MembershipRule> <MonitoringClass>$MPElement[Name="MWSL!Microsoft.Windows.Server.LogicalDisk"]$</MonitoringClass> <RelationshipClass>$MPElement[Name="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$</RelationshipClass> <Expression> <And> <Expression> <SimpleExpression> <ValueExpression> <Property>$MPElement[Name="Windows!Microsoft.Windows.LogicalDevice"]/DeviceID$</Property> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value>C:</Value> </ValueExpression> </SimpleExpression> </Expression> <Expression> <Contained> <MonitoringClass>$MPElement[Name="Windows!Microsoft.Windows.Computer"]$</MonitoringClass> <Expression> <Contains> <MonitoringClass>$MPElement[Name="Demo.App.ServerRole.Class"]$</MonitoringClass> </Contains> </Expression> </Contained> </Expression> </And> </Expression> </MembershipRule>

 

Now, what if we want a group of disks, related to an application, but ONLY if it matches a specific property of the application, like a “Version”?  That’s easy too… you just add an expression to filter on the CONTAINED application class.  Here is an example of that

My membership rule for the group says:

I want a group, of Logical Disks, where the Drive Letter = C: AND I only want disks that are CONTAINED by a Windows Computer object, that also CONTAINS an instance of my custom application class, where that application class has a VERSION property = 4.0

<MembershipRule> <MonitoringClass>$MPElement[Name="MWSL!Microsoft.Windows.Server.LogicalDisk"]$</MonitoringClass> <RelationshipClass>$MPElement[Name="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$</RelationshipClass> <Expression> <And> <Expression> <SimpleExpression> <ValueExpression> <Property>$MPElement[Name="Windows!Microsoft.Windows.LogicalDevice"]/DeviceID$</Property> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value>C:</Value> </ValueExpression> </SimpleExpression> </Expression> <Expression> <Contained> <MonitoringClass>$MPElement[Name="Windows!Microsoft.Windows.Computer"]$</MonitoringClass> <Expression> <Contains> <MonitoringClass>$MPElement[Name="Demo.App.ServerRole.Class"]$</MonitoringClass> <Expression> <SimpleExpression> <ValueExpression> <Property>$MPElement[Name="Demo.App.ServerRole.Class"]/Version$</Property> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value>4.0</Value> </ValueExpression> </SimpleExpression> </Expression> </Contains> </Expression> </Contained> </Expression> </And> </Expression> </MembershipRule>

 

 

The full XML of the MP is below:

<?xml version="1.0" encoding="utf-8"?><ManagementPack ContentReadable="true" SchemaVersion="2.0" OriginalSchemaVersion="1.1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <Manifest> <Identity> <ID>Demo.App</ID> <Version>1.0.0.3</Version> </Identity> <Name>Demo.App</Name> <References> <Reference Alias="SC"> <ID>Microsoft.SystemCenter.Library</ID> <Version>7.0.8437.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="MSIL"> <ID>Microsoft.SystemCenter.InstanceGroup.Library</ID> <Version>7.5.8501.0</Version> <PublicKeyToken>31bf3856ad364e35</PublicKeyToken> </Reference> <Reference Alias="MWSL"> <ID>Microsoft.Windows.Server.Library</ID> <Version>10.0.0.0</Version> <PublicKeyToken>31bf3856ad364e35</PublicKeyToken> </Reference> <Reference Alias="System"> <ID>System.Library</ID> <Version>7.5.8501.0</Version> <PublicKeyToken>31bf3856ad364e35</PublicKeyToken> </Reference> </References> </Manifest> <TypeDefinitions> <EntityTypes> <ClassTypes> <ClassType ID="Demo.App.ServerRole.Class" Accessibility="Public" Abstract="false" Base="Windows!Microsoft.Windows.LocalApplication" Hosted="true" Singleton="false" Extension="false"> <Property ID="Version" Type="string" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" /> </ClassType> <ClassType ID="Demo.App.Disks.Group" Accessibility="Public" Abstract="false" Base="MSIL!Microsoft.SystemCenter.InstanceGroup" Hosted="false" Singleton="true" Extension="false" /> <ClassType ID="Demo.App.Version4.Disks.Group" Accessibility="Public" Abstract="false" Base="MSIL!Microsoft.SystemCenter.InstanceGroup" Hosted="false" Singleton="true" Extension="false" /> </ClassTypes> </EntityTypes> </TypeDefinitions> <Monitoring> <Discoveries> <Discovery ID="Demo.App.Disks.Group.Discovery" Enabled="true" Target="Demo.App.Disks.Group" ConfirmDelivery="false" Remotable="true" Priority="Normal"> <Category>Discovery</Category> <DiscoveryTypes> <DiscoveryRelationship TypeID="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities" /> </DiscoveryTypes> <DataSource ID="GroupPopulationDataSource" TypeID="SC!Microsoft.SystemCenter.GroupPopulator"> <RuleId>$MPElement$</RuleId> <GroupInstanceId>$MPElement[Name="Demo.App.Disks.Group"]$</GroupInstanceId> <MembershipRules> <MembershipRule> <MonitoringClass>$MPElement[Name="MWSL!Microsoft.Windows.Server.LogicalDisk"]$</MonitoringClass> <RelationshipClass>$MPElement[Name="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$</RelationshipClass> <Expression> <And> <Expression> <SimpleExpression> <ValueExpression> <Property>$MPElement[Name="Windows!Microsoft.Windows.LogicalDevice"]/DeviceID$</Property> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value>C:</Value> </ValueExpression> </SimpleExpression> </Expression> <Expression> <Contained> <MonitoringClass>$MPElement[Name="Windows!Microsoft.Windows.Computer"]$</MonitoringClass> <Expression> <Contains> <MonitoringClass>$MPElement[Name="Demo.App.ServerRole.Class"]$</MonitoringClass> </Contains> </Expression> </Contained> </Expression> </And> </Expression> </MembershipRule> </MembershipRules> </DataSource> </Discovery> <Discovery ID="Demo.App.Version4.Disks.Group.Discovery" Enabled="true" Target="Demo.App.Version4.Disks.Group" ConfirmDelivery="false" Remotable="true" Priority="Normal"> <Category>Discovery</Category> <DiscoveryTypes> <DiscoveryRelationship TypeID="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities" /> </DiscoveryTypes> <DataSource ID="GroupPopulationDataSource" TypeID="SC!Microsoft.SystemCenter.GroupPopulator"> <RuleId>$MPElement$</RuleId> <GroupInstanceId>$MPElement[Name="Demo.App.Version4.Disks.Group"]$</GroupInstanceId> <MembershipRules> <MembershipRule> <MonitoringClass>$MPElement[Name="MWSL!Microsoft.Windows.Server.LogicalDisk"]$</MonitoringClass> <RelationshipClass>$MPElement[Name="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$</RelationshipClass> <Expression> <And> <Expression> <SimpleExpression> <ValueExpression> <Property>$MPElement[Name="Windows!Microsoft.Windows.LogicalDevice"]/DeviceID$</Property> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value>C:</Value> </ValueExpression> </SimpleExpression> </Expression> <Expression> <Contained> <MonitoringClass>$MPElement[Name="Windows!Microsoft.Windows.Computer"]$</MonitoringClass> <Expression> <Contains> <MonitoringClass>$MPElement[Name="Demo.App.ServerRole.Class"]$</MonitoringClass> <Expression> <SimpleExpression> <ValueExpression> <Property>$MPElement[Name="Demo.App.ServerRole.Class"]/Version$</Property> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value>4.0</Value> </ValueExpression> </SimpleExpression> </Expression> </Contains> </Expression> </Contained> </Expression> </And> </Expression> </MembershipRule> </MembershipRules> </DataSource> </Discovery> <Discovery ID="Demo.App.ServerRole.Class.Discovery" Enabled="true" Target="Windows!Microsoft.Windows.Server.OperatingSystem" ConfirmDelivery="false" Remotable="true" Priority="Normal"> <Category>Discovery</Category> <DiscoveryTypes> <DiscoveryClass TypeID="Demo.App.ServerRole.Class" /> </DiscoveryTypes> <DataSource ID="DS" TypeID="Windows!Microsoft.Windows.FilteredRegistryDiscoveryProvider"> <ComputerName>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</ComputerName> <RegistryAttributeDefinitions> <RegistryAttributeDefinition> <AttributeName>ServerRoleRegKeyExists</AttributeName> <Path>SOFTWARE\foo</Path> <PathType>0</PathType> <!-- 0=regKey 1=regValue --> <AttributeType>0</AttributeType> <!-- 0=CheckIfExists (Boolean) 1=treat data as (String) 2=treat data as (Integer) --> </RegistryAttributeDefinition> <RegistryAttributeDefinition> <AttributeName>ServerRoleRegKeyVersion</AttributeName> <Path>SOFTWARE\Foo\Version</Path> <PathType>1</PathType> <!-- 0=regKey 1=regValue --> <AttributeType>1</AttributeType> <!-- 0=CheckIfExists (Boolean) 1=treat data as (String) 2=treat data as (Integer) --> </RegistryAttributeDefinition> </RegistryAttributeDefinitions> <Frequency>86400</Frequency> <ClassId>$MPElement[Name="Demo.App.ServerRole.Class"]$</ClassId> <InstanceSettings> <Settings> <Setting> <Name>$MPElement[Name="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Name> <Value>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value> </Setting> <Setting> <Name>$MPElement[Name="System!System.Entity"]/DisplayName$</Name> <Value>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value> </Setting> <Setting> <Name>$MPElement[Name="Demo.App.ServerRole.Class"]/Version$</Name> <Value>$Data/Values/ServerRoleRegKeyVersion$</Value> </Setting> </Settings> </InstanceSettings> <Expression> <SimpleExpression> <ValueExpression> <XPathQuery Type="Boolean">Values/ServerRoleRegKeyExists</XPathQuery> <!-- Common options for XPathQuery Type are "Boolean" "String" "Integer" "Double" --> </ValueExpression> <Operator>Equal</Operator> <!-- Common options for SimpleExpression Operator are "Equal" "NotEqual" "Greater" "Less" "GreaterEqual" "LessEqual" "Like" "NotLike" --> <ValueExpression> <Value Type="Boolean">true</Value> <!-- Common options for XPathQuery Type are "Boolean" "String" "Integer" "Double" --> </ValueExpression> </SimpleExpression> </Expression> </DataSource> </Discovery> </Discoveries> </Monitoring> <LanguagePacks> <LanguagePack ID="ENU" IsDefault="true"> <DisplayStrings> <DisplayString ElementID="Demo.App"> <Name>Demo App </Name> </DisplayString> <DisplayString ElementID="Demo.App.Disks.Group"> <Name>Demo App Disks Group</Name> </DisplayString> <DisplayString ElementID="Demo.App.Disks.Group.Discovery"> <Name>Demo App Disks Group Discovery</Name> <Description /> </DisplayString> <DisplayString ElementID="Demo.App.Version4.Disks.Group"> <Name>Demo App Version 4 Disks Group</Name> </DisplayString> <DisplayString ElementID="Demo.App.Version4.Disks.Group.Discovery"> <Name>Demo App Version 4 Disks Group Discovery</Name> <Description /> </DisplayString> <DisplayString ElementID="Demo.App.ServerRole.Class"> <Name>Demo App ServerRole Class</Name> </DisplayString> <DisplayString ElementID="Demo.App.ServerRole.Class" SubElementID="Version"> <Name>Version</Name> </DisplayString> <DisplayString ElementID="Demo.App.ServerRole.Class.Discovery"> <Name>Demo App ServerRole Class Discovery</Name> </DisplayString> </DisplayStrings> </LanguagePack> </LanguagePacks> </ManagementPack>

 

 

Other examples:

 

A Group of Logical Disks (that do NOT have drive letter C: ) but are CONTAINED by Computers in some OTHER GROUP:

<MembershipRule> <MonitoringClass>$MPElement[Name="MWSL!Microsoft.Windows.Server.LogicalDisk"]$</MonitoringClass> <RelationshipClass>$MPElement[Name="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$</RelationshipClass> <Expression> <And> <Expression> <SimpleExpression> <ValueExpression> <Property>$MPElement[Name="Windows!Microsoft.Windows.LogicalDevice"]/Name$</Property> </ValueExpression> <Operator>NotEqual</Operator> <ValueExpression> <Value>C:</Value> </ValueExpression> </SimpleExpression> </Expression> <Expression> <Contained> <MonitoringClass>$MPElement[Name="Windows!Microsoft.Windows.Computer"]$</MonitoringClass> <Expression> <Contained> <MonitoringClass>$MPElement[Name="MicrosoftSQLServerLibrary!Microsoft.SQLServer.ComputerGroup"]$</MonitoringClass> </Contained> </Expression> </Contained> </Expression> </And> </Expression> </MembershipRule>

 

We add Health Service Watchers to Computer Groups using the same method of Contains/Contained.  The HealthServiceWatcher CONTAINS a HealthService, that is CONTAINED by a Windows Computer.  In this case, the $Target/Id$ is simply the group itself.  One membership rule populates the group with Windows Computers, the other membership rule populates the Watchers that are related to the Computers contained in the group.

<MembershipRules> <MembershipRule> <MonitoringClass>$MPElement[Name="Windows!Microsoft.Windows.Computer"]$</MonitoringClass> <RelationshipClass>$MPElement[Name="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$</RelationshipClass> <Expression> <Contains> <MonitoringClass>$MPElement[Name="##ClassID##"]$</MonitoringClass> </Contains> </Expression> </MembershipRule> <MembershipRule> <MonitoringClass>$MPElement[Name="SC!Microsoft.SystemCenter.HealthServiceWatcher"]$</MonitoringClass> <RelationshipClass>$MPElement[Name="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$</RelationshipClass> <Expression> <Contains> <MonitoringClass>$MPElement[Name="SC!Microsoft.SystemCenter.HealthService"]$</MonitoringClass> <Expression> <Contained> <MonitoringClass>$MPElement[Name="Windows!Microsoft.Windows.Computer"]$</MonitoringClass> <Expression> <Contained> <MonitoringClass>$Target/Id$</MonitoringClass> </Contained> </Expression> </Contained> </Expression> </Contains> </Expression> </MembershipRule> </MembershipRules>

 

You can use this same relationship if you just wanted groups of Watcher objects, related to an application:

<MembershipRule> <MonitoringClass>$MPElement[Name="SC!Microsoft.SystemCenter.HealthServiceWatcher"]$</MonitoringClass> <RelationshipClass>$MPElement[Name="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$</RelationshipClass> <Expression> <Contains> <MonitoringClass>$MPElement[Name="SC!Microsoft.SystemCenter.HealthService"]$</MonitoringClass> <Expression> <Contained> <MonitoringClass>$MPElement[Name="Windows!Microsoft.Windows.Computer"]$</MonitoringClass> <Expression> <Contains> <MonitoringClass>$MPElement[Name="##ClassID##"]$</MonitoringClass> </Contains> </Expression> </Contained> </Expression> </Contains> </Expression> </MembershipRule>

9 Comments

  1. ENDRE N

    Hi Kevin! Thank you this great solution. BUT I have a special scenario. Can I filter the class in the CONTAINS section?
    Based on your example:
    I want a group, of Logical Disks, where the Drive Letter = C: AND I only want disks that are CONTAINED by a Windows Computer object, that also CONTAIN an instance of my custom application class WITH SPECIFIED VERSION. VERSOIN is an attribute of the custom application class.

    Thanks in advance!

  2. David

    Kevin,

    Created group of disks for a group of another class as in your example.

    The expression conversion by SCOM to the actual SQL statement results in a query against “RecursiveMembership” table for items with “Depth > 0”

    Have found this makes a rather negative performance impacts to the Ops DB due to the nature of that one portion of the statement…

    “AND RM.[ContainedEntityId] = MTV_xxxx$LogicalDisk.[BaseManagedEntityId]”

    In our case, we have over 4000 agents and causes a really major impact…..

    Do you have any suggestions?

    • kevinholman

      That’s really interesting. What is the “impact” that you see, how often does it happen, and how did you come to the conclusion this was it?

  3. Michael Stefansen

    Hi Kevin,
    I really enjoy reading when you put all you knowledge out to us, there are so many amazing posts which solves so many frustrations, I believe 🙂 Thanks!
    I have a need for creating a group for all logical disks on Exchange servers, but only the disks where the Exchange database is stored. That disk should not go under 10% free space and I want to do an override for that group to check for that.
    Is there an easy solution to that?

    • Kevin Holman

      You would create the group very similar to this group example. However, you need some way to filter if the Exchange database exists – most of the time we do that by drive letters, assuming your exchange database drives follow a standard. If they do not – then you’d need to find another way – by using existing discovered attributes, or by creating a custom script based discovery to populate members of the group, which would be much more complex.

Leave a Reply

Your email address will not be published.