Monitoring Objects

Monitoring objects are the instances that are discovered in SCOM. They are identified by unique values for key properties as defined by the class(es) that they are as well as the key properties of their host, if applicable. Their identity is solidified by the first non-abstract class in the objects class hierarchy, even though there may still exist a hierarchy of non-abstract classes that derive from this class. For instance, a computer is defined by its System.Computer class, even though it is also a System.Windows.Computer and potentially a MyCompany.SpecialComputer, both of which derive from System.Computer. It is important to note that these additional non-abstract classes do not in any way change the identity of the object itself and can be thought of as roles.

Since a monitoring object is a representation of an instantiated class, it really represents a meta-object in a way. Early on, we were trying to figure out if we want strongly typed monitoring objects, such as Computer or Server, but for the most part decided against it, with a few exceptions to SCOM specific classes like ManagementServer. Given that, the MonitoringObject, in it's most basic form, is a property bag of values for all the class(es) properties of the object as well as the objects host(s).

When we store monitoring objects in the database, they are stored in two places. We have a general store where common attributes of all monitoring objects are maintained, such as Name, Id and class list (what classes the object is) and a dynamically generated view per identifying class that gets populated with class values. As such, all SDK methods that return MonitoringObject must make at least two queries to construct the object. If the response is heterogeneous in object class, there are even more queries performed. This fact and it's performance implications led to the SDK exposing a full MonitoringObject that represents the property bag as mentioned above as well as a stripped PartialMonitoringClass that includes all the same functionality as MonitoringObject, but does not include any property values or property value related methods. Any method returning PartialMonitoringObject will always perform a single database query and thus is the recommended approach when working with these objects, unless the properties are necessary. The only additional method on MonitoringObject that is not on PartialMonitoringObject is:

 public object GetMonitoringPropertyValue(MonitoringClassProperty property)

Please note that this method can be used properties of the monitoring object itself, or any key properties of any host class.

Before diving into all the various ways to query for monitoring objects, I wanted to go through some of features of the object (both MonitoringObject and PartialMonitoringObject) itself. First, there is a public event available on the object:

 public event EventHandler<MonitoringObjectMembershipChangedEventArgs> OnRelatedEntitiesChanged

This event will get signaled any time any object in the containment hierarchy of the current object is changed. The event includes the Id of the object whose contained members changed, but does NOT include what objects actually changed; a query would need to be performed to get contained objects and compare accordingly.

The object also contains the following properties for quick reference without needing a full Monitoring Object

         public string Name
        public string Path
        public string DisplayName
        public string FullName
        public bool IsManaged
        public DateTime LastModified
        public HealthState HealthState
        public DateTime? StateLastModified
        public bool IsAvailable
        public DateTime? AvailabilityLastModified
        public bool InMaintenanceMode
        public DateTime? MaintenanceModeLastModified
        public ReadOnlyCollection<Guid> MonitoringClassIds
        public Guid LeastDerivedNonAbstractMonitoringClassId

Name is the key value(s) of the monitoring object, while DisplayName is the same as name unless a friendly display name was specified by the discovery source via the DisplayName property defined on the System.Entity class. Path is the concatenated names of the hosts, while FullName is the uniquely identifying full name of the current instance, including name, path and class name. The HealthState of the System.EntityHealth monitor for the object is populated, as is the currently IsAvailable property (which is a function of the health service that is currently monitoring this object being available) and whether or not the object is in maintenance mode. IsManaged is always true and is not used. The MonitoringClassIds are all the non-abstract classes this object is, and the LeastDerivedNonAbstractMonitoringClassId is what it says it is, namely the class that brings in the identity of the object, just with a really long name :-).

There are a ton of methods on this object, that I will leave that for you to browse through. I will go through some as the topics come up with future posts.

Now, how do you get this objects? Well, first, let's go over MonitoringObjectGenericCriteria and MonitoringObjectCriteria. MonitoringObjectGenericCriteria allows you to query by generic properties shared across all monitoring objects. This is the list of properties you can use:

Id
Name
Path
FullName
DisplayName
LastModified
HealthState
StateLastModified
IsAvailable
AvailabilityLastModified
InMaintenanceMode
MaintenanceModeLastModified

MonitoringObjectCriteria uses the same properties and allows you to query for monitoring objects by specific property values, as defined on the class(es) of the objects (such as PrincipalName on Computer), however, you can NOT use non-abstract classes. Note that when querying by MonitoringObjectCriteria, MonitoringObject instances are always returned as we have to make a query on both tables in the database anyway.

What follows is an overview of the methods that are available for retrieving MonitoringObject(s) and PartialMonitoringObject(s). I won't go over all of them as hopefully the docs/Intellisense can help you find what you need.

These are methods that accept criteria as accessible on the ManagementGroup object:

 public ReadOnlyCollection<MonitoringObject> GetMonitoringObjects(MonitoringObjectGenericCriteria criteria)
public ReadOnlyCollection<MonitoringObject> GetMonitoringObjects(MonitoringObjectCriteria criteria)
public ReadOnlyCollection<MonitoringObject> GetMonitoringObjects(ICollection<MonitoringObjectCriteria> criteriaCollection)
public ReadOnlyCollection<PartialMonitoringObject> GetPartialMonitoringObjects(MonitoringObjectGenericCriteria criteria)

These are methods that accept criteria as accessible on the monitoring object instance itself. TraversalDepth can be OneLevel or Recursive and determines whether we return immediately contained instances, or all contained instances:

 public ReadOnlyCollection<MonitoringObject> GetRelatedMonitoringObjects(MonitoringObjectGenericCriteria criteria, TraversalDepth traversalDepth)
public ReadOnlyCollection<PartialMonitoringObject> GetRelatedPartialMonitoringObjects(MonitoringObjectGenericCriteria criteria, TraversalDepth traversalDepth)

These methods allow you to specify a class as your criteria, including abstract classes, and are found on ManagementGroup (similar methods are available on MonitoringObject with TraversalDepth as a parameter):

 public ReadOnlyCollection<MonitoringObject> GetMonitoringObjects(MonitoringClass monitoringClass)
public ReadOnlyCollection<PartialMonitoringObject> GetPartialMonitoringObjects(MonitoringClass monitoringClass)

For getting related objects for multiple instances (the UI State View uses these methods), ManagementGroup allows you to get related object to a collection of objects by class, relationship type or MonitoringObjectCriteria (MonitoringObject also has similar methods for a single object):

 public Dictionary<T, ReadOnlyCollection<MonitoringObject>> GetRelatedMonitoringObjects<T>(ICollection<T> monitoringObjects, MonitoringClass monitoringClass, TraversalDepth traversalDepth) where T : PartialMonitoringObject

public Dictionary<T, ReadOnlyCollection<MonitoringObject>> GetRelatedMonitoringObjects<T>(ICollection<T> monitoringObjects, MonitoringObjectCriteria criteria, TraversalDepth traversalDepth) where T : PartialMonitoringObject

public Dictionary<T, ReadOnlyCollection<MonitoringObject>> GetRelatedMonitoringObjects<T>(ICollection<T> monitoringObjects, MonitoringRelationshipClass relationshipClass, TraversalDepth traversalDepth) where T : PartialMonitoringObject

public Dictionary<T, ReadOnlyCollection<PartialMonitoringObject>> GetRelatedPartialMonitoringObjects<T>(ICollection<T> monitoringObjects, MonitoringClass monitoringClass, TraversalDepth traversalDepth) where T : PartialMonitoringObject

public Dictionary<T, ReadOnlyCollection<PartialMonitoringObject>> GetRelatedPartialMonitoringObjects<T>(ICollection<T> monitoringObjects, MonitoringRelationshipClass relationshipClass, TraversalDepth traversalDepth) where T : PartialMonitoringObject

This list isn't exhaustive, but it's pretty close. If you have any particular scenarios that you are confused about with regard to these methods and how best to accomplish a particular query, shoot me an email or post a comment. Also note that MonitoringRelationship is another class that has a source MonitoringObject and a target MonitoringObject included in the class itself and provides another convenient way to retrieve monitoring objects, but that is for another post.

Comments

  • Anonymous
    February 12, 2009
    What is the easiest way to get all monitoring objects?  The powershell equivalent of Get-MonitoringObject with no arguments?

  • Anonymous
    February 12, 2009
    I'd say it would be GetMonitoringObjects(MonitoringClass) and pass in System.Entity.

  • Anonymous
    March 21, 2010
    Thanks for this post, I am new to C# and trying to convert certain Powershell scripts to C#. In this case I need to extract a property from a custom class based on Windows Computer. This PS query provides exactly what I need: get-monitoringclass -name:Custom.Classes.Groups.MyCompany.WindowsComputer | get-monitoringobject | where {$.displayname -eq $computerName} |get-monitoringobjectproperty | where {$.displayname -eq 'Help Desk Inbox'} This C# code to grab all properties compiles but runtime errors--and I just want the 'Help Desk Inbox' property anyway ManagementGroup mg = new ManagementGroup("localhost"); MonitoringClassCriteria classCriteria = new MonitoringClassCriteria("Name = 'Custom.Classes.Groups.MyCompany.WindowsComputer'"); ReadOnlyCollection<MonitoringClass> monitoringClasses = mg.GetMonitoringClasses(classCriteria); string computerName = "Hostname.Company.com"; MonitoringObjectCriteria objectCriteria = new MonitoringObjectCriteria("DisplayName = " + computerName, monitoringClasses[0]); ReadOnlyCollection<MonitoringObject> monitoringObjects = mg.GetMonitoringObjects(objectCriteria); foreach (MonitoringClassProperty property in monitoringObjects[0].GetMonitoringProperties()) { Console.WriteLine(property.Name + " = " + monitoringObjects[0].GetMonitoringPropertyValue(property)); } What am I overlooking in trying to get the single monitoring object property? Thanks!

  • Anonymous
    March 22, 2010
    The comment has been removed

  • Anonymous
    March 23, 2010
    You are right, that's what I thought. Quoting with variables in C# has been more challenging than any other language. I expected this to work: new MonitoringObjectCriteria("DisplayName = " + 'computerName', monitoringClasses[0]); but VS won't compile, stating 'too many characters in character literal'. And of course double quoting compiles, but the variable is then a literal string like with any other language. I have tried building the Name = string first then using this variable in the parens, but it does not work either. This is primarily where I am stuck, but also wonder if it is possible to get the property I want without first building a collection of properties, then looping through them all to get the one I need. You must be very busy, and appreciate your help, this is great.

  • Anonymous
    March 23, 2010
    Try string.Format("DisplayName = '{0}'", computerName).

  • Anonymous
    March 23, 2010
    You beat me to it! Just figured that out a moment ago thanks to a Google search. Felt good to figure it out. MonitoringObjectCriteria objectCriteria = new MonitoringObjectCriteria(string.Format("DisplayName = '{0}'", computerName), monitoringClasses[0]); Now that I have my property output via looping through a collection, any way to bypass the collection, or must that be built to get at individual properties? Thank you again!

  • Anonymous
    March 23, 2010
    No, you need to get the whole instance back to get the property, so you're doing it the best way.

  • Anonymous
    March 23, 2010
    Appreciate the quick and patient responses to my noob questions. Thank you for everything Jakub!

  • Anonymous
    August 17, 2010
    Can you please let me know the port/s used by SCOM for monitoring the non windows machines? Also please let me know what should be the preferred windows account used by the MonitoringHost.exe processes.

  • Anonymous
    August 18, 2010
    The comment has been removed