JAMA00

SCOM 2007 R2

Targeting rules and customers

Posted by MarcKlaver on May 6, 2010

We are managing several customers with one management group and one management environment. Some rules are very customer specific and we wanted to prevent rules specific for customer A being visible at customer B (and all other customers).

To accomplish this, we tried this:

  • We targeted a disabled rule to the windows computer object and enabled the rule for targets specific for customer A (using our computer attributes we also use for customer group population, see also this link). Unfortunately, this didn’t work. The rule ended up at all windows computer targets, regardless of the rule being enabled or disabled for the target. 
  • Next we tried a new management pack, with only disabled rules. Again the rules were distributed over all customers.

So our conclusion is that the agent itself determines if a rule is enabled/disabled, not the RMS. The RMS only checks if the agent has a target for a rule/mp.

To prevent the rules from being distributed to customer B (and all other customers), we needed to be able to target only to computers for customer A. The only option we found was to create a class to target computers at a customer level. Again we used our registry key we also use for the group population. But this time it is used to discover a class, specific to the customer.

We decided that it wasn’t a problem that a customer specific rule was available on all servers of a single customer, so we created one class for each customer:

image 

or in XML:

<TypeDefinitions>
  <EntityTypes>
    <ClassTypes>
      <ClassType ID="jama.CustomerId.CustomerA" Accessibility="Public" Abstract="false" Base="Windows!Microsoft.Windows.ComputerRole" Hosted="true" Singleton="false"/>
      <ClassType ID="jama.CustomerId.CustomerB" Accessibility="Public" Abstract="false" Base="Windows!Microsoft.Windows.ComputerRole" Hosted="true" Singleton="false"/>
      <ClassType ID="jama.CustomerId.CustomerC" Accessibility="Public" Abstract="false" Base="Windows!Microsoft.Windows.ComputerRole" Hosted="true" Singleton="false"/>
      <ClassType ID="jama.CustomerId.CustomerD" Accessibility="Public" Abstract="false" Base="Windows!Microsoft.Windows.ComputerRole" Hosted="true" Singleton="false"/>
    </ClassTypes>
  </EntityTypes>
</TypeDefinitions>

Next we created a discovery, to discover the “customer” classes:

image

The discovery will discover any customer class we have defined:

image

or in XML:

<DiscoveryTypes>
  <DiscoveryClass TypeID="jama.CustomerId.CustomerA" />
  <DiscoveryClass TypeID="jama.CustomerId.CustomerB" />
  <DiscoveryClass TypeID="jama.CustomerId.CustomerC" />
  <DiscoveryClass TypeID="jama.CustomerId.CustomerD" />
</DiscoveryTypes>

The discovery itself is done with a script. Originally I wanted to create this code:

strCustomerId = ucase(jamaGetAttribute(STR_ATTRIBUTE_CUSTOMER_ID)) ‘ retrieve customer id
if(strCustomerId <> "") then
    set g_objClass = g_objDiscoveryData.CreateClassInstance("$MPElement[Name=’jama.CustomerId." & strCustomerId & "’]$")
end if

But the authoring console didn’t like that (never checked it with the operator console, but I assume the import will fail also), because it didn’t know anything about the element “jama.CustomerId." & strCustomerId” 🙂 When checking the management pack, it also wants to resolve all “MPElement” names in the scripts, but it didn’t use the variables.

So I now created a switch statement, for all customer names in the management pack:

strCustomerId = ucase(jamaGetAttribute(STR_ATTRIBUTE_CUSTOMER_ID))

if(strCustomerId <> "") then 
     select case strCustomerId
         case "CUSTOMERA" set g_objClass = g_objDiscoveryData.CreateClassInstance("$MPElement[Name=’jama.CustomerId.CustomerA’]$")
         case "CUSTOMERB" set g_objClass = g_objDiscoveryData.CreateClassInstance("$MPElement[Name=’jama.CustomerId.CustomerB’]$")
         case "CUSTOMERC" set g_objClass = g_objDiscoveryData.CreateClassInstance("$MPElement[Name=’jama.CustomerId.CustomerC’]$")
         case "CUSTOMERD" set g_objClass = g_objDiscoveryData.CreateClassInstance("$MPElement[Name=’jama.CustomerId.CustomerD’]$")
     end select

    g_objClass.AddProperty "$MPElement[Name=’Windows!Microsoft.Windows.Computer’]/PrincipalName$", "$Target/Property[Type=’Windows!Microsoft.Windows.Computer’]/PrincipalName$"

    g_objClass.AddProperty "$MPElement[Name=’System!System.Entity’]/DisplayName$", "$Target/Property[Type=’Windows!Microsoft.Windows.Computer’]/PrincipalName$"
     g_objDiscoveryData.AddInstance(g_objClass)
end if

So when all combined, the final xml file will result in this:

<?xml version="1.0" encoding="utf-8"?><ManagementPack ContentReadable="true" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <Manifest>
    <Identity>
      <ID>jamaClass</ID>
      <Version>1.0.0.0</Version>
    </Identity>
    <Name>jamaClass</Name>
    <References>
      <Reference Alias="System">
        <ID>System.Library</ID>
        <Version>6.0.6278.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="Windows">
        <ID>Microsoft.Windows.Library</ID>
        <Version>6.0.6278.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
    </References>
  </Manifest>
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        <ClassType ID="jama.CustomerId.CustomerA" Accessibility="Public" Abstract="false" Base="Windows!Microsoft.Windows.ComputerRole" Hosted="true" Singleton="false"/>
        <ClassType ID="jama.CustomerId.CustomerB" Accessibility="Public" Abstract="false" Base="Windows!Microsoft.Windows.ComputerRole" Hosted="true" Singleton="false"/>
        <ClassType ID="jama.CustomerId.CustomerC" Accessibility="Public" Abstract="false" Base="Windows!Microsoft.Windows.ComputerRole" Hosted="true" Singleton="false"/>
        <ClassType ID="jama.CustomerId.CustomerD" Accessibility="Public" Abstract="false" Base="Windows!Microsoft.Windows.ComputerRole" Hosted="true" Singleton="false"/>
      </ClassTypes>
    </EntityTypes>
  </TypeDefinitions>
  <Monitoring>
    <Discoveries>
       <Discovery ID="jama.CustomerId.Server.Discovery" Enabled="true" Target="Windows!Microsoft.Windows.Server.Computer" ConfirmDelivery="false" Remotable="true" Priority="Normal">
         <Category>Discovery</Category>
           <DiscoveryTypes>
             <DiscoveryClass TypeID="jama.CustomerId.CustomerA" />
             <DiscoveryClass TypeID="jama.CustomerId.CustomerB" />
             <DiscoveryClass TypeID="jama.CustomerId.CustomerC" />
             <DiscoveryClass TypeID="jama.CustomerId.CustomerD" />
           </DiscoveryTypes>
           <DataSource ID="DS" TypeID="Windows!Microsoft.Windows.TimedScript.DiscoveryProvider">
             <IntervalSeconds>86400</IntervalSeconds>
             <SyncTime />
             <ScriptName>jama.CustomerId.Server.Discovery.vbs</ScriptName>
             <Arguments />
             <ScriptBody><![CDATA[‘
option explicit
setLocale("en-us")
on error goto 0

const EVENT_ID_FOUND_CLASS   = 110

const STR_ATTRIBUTE_CUSTOMER_ID = "customer_id"
const HKLM                      = &H80000002
const STR_ATTRIBUTE_KEY         = "SOFTWARE\jama00\OpsMgr2007\attributes"

dim g_objAPI
dim g_objClass
dim g_objDiscoveryData

jamaInitialize()
jamaCreateDiscovery()
g_objAPI.Return(g_objDiscoveryData)

function jamaInitialize()
    set g_objAPI           = CreateObject("MOM.ScriptAPI")
    set g_objDiscoveryData = g_objAPI.CreateDiscoveryData(0, "$MPElement$", "$Target/Id$")
end function

function jamaCreateDiscovery()
    dim strCustomerId

   strCustomerId = ucase(jamaGetAttribute(STR_ATTRIBUTE_CUSTOMER_ID))
    if(strCustomerId <> "") then
        jamaWriteLog EVENT_ID_FOUND_CLASS, "Discoverd class: jama.CustomerId." & strCustomerId
        select case strCustomerId
            case "CUSTOMERA" set g_objClass = g_objDiscoveryData.CreateClassInstance("$MPElement[Name=’jama.CustomerId.CustomerA’]$")
            case "CUSTOMERB" set g_objClass = g_objDiscoveryData.CreateClassInstance("$MPElement[Name=’jama.CustomerId.CustomerB’]$")
            case "CUSTOMERC" set g_objClass = g_objDiscoveryData.CreateClassInstance("$MPElement[Name=’jama.CustomerId.CustomerC’]$")
            case "CUSTOMERD" set g_objClass = g_objDiscoveryData.CreateClassInstance("$MPElement[Name=’jama.CustomerId.CustomerD’]$")
        end select
        g_objClass.AddProperty "$MPElement[Name=’Windows!Microsoft.Windows.Computer’]/PrincipalName$", "$Target/Property[Type=’Windows!Microsoft.Windows.Computer’]/PrincipalName$"
        g_objClass.AddProperty "$MPElement[Name=’System!System.Entity’]/DisplayName$", "$Target/Property[Type=’Windows!Microsoft.Windows.Computer’]/PrincipalName$"
        g_objDiscoveryData.AddInstance(g_objClass)
    end if
end function

function jamaGetAttribute(byval strAttribute)
    dim strResult
    dim objReg

    strResult = ""
    on error resume next
        err.clear
        set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
        if(err.number <> 0) then
            strResult = ""
        else
            objReg.GetStringValue HKLM, STR_ATTRIBUTE_KEY, strAttribute, strResult
            if(err.number <> 0) then
                strResult = ""
            elseif(isnull(strResult)) then
                strResult = ""
            end if
        end if
    on error goto 0

    jamaGetAttribute = strResult
end function

function jamaWriteLog(iEventId, strMsg)
    dim bEnabled : bEnabled = true      ‘ Set to false to disable logging.

    if(bEnabled) then
        dim objAPI
        dim strTemp

        set objAPI = CreateObject("MOM.ScriptAPI")
        if((iEventId >= 100) and (iEventId < 20000)) then
            call objAPI.LogScriptEvent(wscript.scriptname, iEventId, 4, strMsg)
        else
            strTemp = "Out of range event id found: " & cstr(iEventId) & ". Original message: " & strMsg
            call objAPI.LogScriptEvent(wscript.scriptname, 0, 4, strTemp)
        end if
    end if
end function
]]></ScriptBody>
          <TimeoutSeconds>300</TimeoutSeconds>
        </DataSource>
      </Discovery>
    </Discoveries>
  </Monitoring>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="false">
      <DisplayStrings>
        <DisplayString ElementID="jamaClass">
          <Name>jamaClass</Name>
          <Description>Agent version: 3.1.0  build 442 </Description>
        </DisplayString>
        <DisplayString ElementID="jama.CustomerId.Server.Discovery">
          <Name>jama.CustomerId.Server.Discovery (name)</Name>
          <Description>jama.CustomerId.Server.Discovery (description)</Description>
        </DisplayString>
        <DisplayString ElementID="jama.CustomerId.CustomerA">
          <Name>jama.CustomerId.CustomerA (name)</Name>
          <Description>jama.CustomerId.CustomerA (description)</Description>
        </DisplayString>
        <DisplayString ElementID="jama.CustomerId.CustomerB">
          <Name>jama.CustomerId.CustomerB (name)</Name>
          <Description>jama.CustomerId.CustomerB (description)</Description>
        </DisplayString>
        <DisplayString ElementID="jama.CustomerId.CustomerC">
          <Name>jama.CustomerId.CustomerC (name)</Name>
          <Description>jama.CustomerId.CustomerC (description)</Description>
        </DisplayString>
        <DisplayString ElementID="jama.CustomerId.CustomerD">
          <Name>jama.CustomerId.CustomerD (name)</Name>
          <Description>jama.CustomerId.CustomerD (description)</Description>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPack>

And this must be adjusted for every new customer we define in our environment and yes this is fully scripted 🙂 The last thing to do is to seal the management pack, so we can use it in other management packs. This is done with the mpseal.exe from the installation CD:

 

MPSeal.exe jamaClass.xml /I .\mp /keyfile privatekey_JAMA.snk /company "JAMA" /outdir .\sealed

Note the “/I .\mp” option. I have created a subdirectory with all referenced management packs called “mp”. You must supply the mpseal.exe with the referenced management packs before it is able to seal the management pack. The file “privatekey_JAMA.snk” contains our private key we use for sealing all our management packs. The final result will be stored in the “sealed” sub directory.

 

So now I finally can select a target that only exists at a customer site:

image

Default disabling the rule, will give you the possibility to override the rule for one or just a few servers within the customer targeted (CustomerC in this example) without distributing the rule(s) to other customers.

Advertisements

2 Responses to “Targeting rules and customers”

  1. snajgel said

    Hi!

    Did you ever consider using the Service Provider MP from Microsoft? Im looking in to that for a customer of mine, but I cant figure out how to make it pick up gateways instead of SCE-installations.

    Regards
    Snajgel

    • MarcKlaver said

      No. I never knew about this MP. And looking at it, it depends on an essentials installation. But generally it does the same, however it looks in the registry key which should exist in an essentials installation.

      Our solution depends on registry settings set during the installation of the agent (scripted manual installation). And should work for every SCOM implementation.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: