At my current client, server codes are used to identify a set of servers serving a single purpose. For example: XMS20 is the servercode for all SCOM management servers belonging to a certain management group. This code is inserted into the registry of each server under a specific key.
The goal was to have one group for each code, which would contain all servers having the code.
As there are lots of servercodes (hundreds!), creating a group for each single one would be time-consuming. Also, the servercode-system is volatile in nature: some disappear and some new ones are added from time to time. What we needed was something that could dynamically create the groups for us and maintain them automatically.
As it appears, this is perfectly possible in SCOM, with one drawback (more on that later).
So what is the trick?
Each group that you create manually in SCOM is a derivative class from Microsoft.SystemCenter.InstanceGroup. Because you create this group yourself, it isn’t created by a discovery, it just “starts to exist” after you click finish. The term that is used to mark such an object is a ‘singleton’. A singleton is a class which also is an object at the same time. Singletons in SCOM are not hosted, they are maintained by the management servers.
The thing that we have to do is define a derivative class for Microsoft.SystemCenter.InstanceGroup, but without making it a singleton. This can be done by making sure the box that controls this property isn’t checked. This way our group class can be created on the fly, by using a discovery (targeted to windows computer) to create one instead of having a singleton property set.
What is important is that we create a key attribute on the class. Why? A key attribute is used to mark an instance of a class as unique. This means that should a discovery define 2 instances of a class which have an identical value as key attribute, they will be merged in a single object. Translating to our scenario, we want to prevent that for each servercode being collected from a server’s registry, a new group is created. Therefore, we define a key-attribute ‘ServerCode’ on our new group-class. This will merge subsequent discoveries of the same servercode into one group-object.
Ok, now we have unique groups, we must populate them. This can be easily done from within the same discovery. First I want to talk about SCOM-relationships: relationships define how objects are positioned in a hierarchy. Specifically to our scenario: the base-class of our class is still ‘Microsoft.SystemCenter.InstanceGroup’. This base-class has a relationship called “InstanceGroupContainsEntities”, which specifies that the class may contain any item. Because we derivate from this class, we automatically inherit this relationship as well. So the only thing we have to do is create an instance of this relationship in our discovery, put the instance of the servercode-group as parent and put the Windows-Computer object as a child. Where will we get this Windows Computer object? We will create it! A Windows Computer object can be created by a custom discovery, without worrying about breaking the built-in discoveries (unless you really try to). By defining an instance using only PrincipalName (it is the key attribute and must always be defined), we can have a representation of the very Windows computer object we are targeting with our discovery and use it to complete the relationship instance.
I know this is a lot of heavy stuff, therefore I will provide a break down on what kind of discovery we will be doing. A vb script will be ran on each server and do the following:
- Retrieve the servercode from registry
- Create a new instance of our class with the servercode from registry set as key attribute
- Create an instance of Windows.Computer (using only the principalname as attribute)
- Create an instance of the “InstanceGroupContainsEntities”-relationship, and add the 2 previous instance as respective parent and child
- Return the discovery data to SCOM
This will create a populated group, which is usable for overrides and subscription management!
But there is one more thing! Because there will be multiple servers submitting discovery data for a single group-object, we will have to enable proxying on each server. This might be a high price to pay, but you do get a fully dynamic group management system in return. This might be a showstopper, but this is your decision to make.
I provide the VBScript used to perform the discovery (for this one a derivative class is used for the Windows Computer object as well, but this isn’t mandatory):
Set oAPI = CreateObject(“MOM.ScriptAPI”)
Set oArgs = WScript.Arguments
‘ Check for the required script arguments.
if oArgs.Count < 3 Then
‘ If the script is called without the required arguments,
‘ create an information event and then quit.
Call oAPI.LogScriptEvent(“CustomBaseDiscovery.vbs”,101,1, _
“Script was called with fewer than three arguments and was not executed.”)
Dim SourceID, ManagedEntityId, TargetComputer
SourceId = oArgs(0) ‘ The GUID of the discovery object that launched the script.
ManagedEntityId = oArgs(1) ‘ The GUID of the computer class targeted by the script.
TargetComputer = oArgs(2) ‘ The hostname of the computer targeted by the script.
Dim oDiscoveryData, oInstManagedServer,oInstServerGroup,ServerCode,arrSubKeys
Const HKEY_LOCAL_MACHINE = &H80000002
If IsNull (ServerCode) Then ServerCode = “NA”
‘Add Computer instance
Set oDiscoveryData = oAPI.CreateDiscoveryData(0, SourceID, ManagedEntityID)
set oInstManagedServer = oDiscoveryData.CreateClassInstance(“$MPElement[Name=’JVM-NET.Computer’]$”)
call oInstManagedServer.AddProperty(“$MPElement[Name=’WindowsLibrary!Microsoft.Windows.Computer’]/PrincipalName$”, TargetComputer)
call oInstManagedServer.AddProperty(“$MPElement[Name=’Computer’]/ServerCode$”, ServerCode)
‘Add ServerGroup instance
set oInstServerGroup = oDiscoveryData.CreateClassInstance(“$MPElement[Name=’JVM-NET.ServerCodeGroup’]$”)
call oInstServerGroup.AddProperty(“$MPElement[Name=’MP.ServerCodeGroup’]/ServerCode$”, ServerCode)
call oInstServerGroup.AddProperty(“$MPElement[Name=’System!System.Entity’]/DisplayName$”, ServerCode)
if Err.Number <> 0 Then
Call oAPI.LogScriptEvent(“CustomBaseDiscovery.vbs”,104,1, “Script Error : Can’t create ServerGroup (” & Err.Number & “) ” & Err.Description)
‘Create a relationship between ServerGroup and Windows Computer
set oInstWindowsComputer = oDiscoveryData.CreateClassInstance(“$MPElement[Name=’WindowsLibrary!Microsoft.Windows.Computer’]$”)
call oInstWindowsComputer.AddProperty(“$MPElement[Name=’WindowsLibrary!Microsoft.Windows.Computer’]/PrincipalName$”, TargetComputer)
Set oRelationship = oDiscoveryData.CreateRelationshipInstance(“$MPElement[Name=’SystemCenterInstanceGroupLibrary!Microsoft.SystemCenter.InstanceGroupContainsEntities’]$”)
oRelationship.Source = oInstServerGroup
oRelationship.Target = oInstWindowsComputer
if Err.Number <> 0 Then
Call oAPI.LogScriptEvent(“CustomBaseDiscovery.vbs”,104,1, “Script Error : Can’t create ServerGroup to Computer relationship (” & Err.Number & “) ” & Err.Description)