JAMA00

SCOM 2007 R2

Archive for May, 2010

Setting an override on a rule with PowerShell (OpsMgr snapin part 3)

Posted by MarcKlaver on May 12, 2010

A few examples on how to use the two cmdlets.

To try the cmdlets, type:

add-pssnapin mkropsmgr

This command adds the PowerShell snapin. This is required to use the cmdlets. You should only have to use this once in every session you run.

Get-RuleParameter -ClassCriteria "DisplayName like ‘%’" -RuleCriteria "DisplayName like ‘%’" –Verbose

This command will show you all overridable parameters from all rules. If you want to see the whole output, you should be patient 🙂 This command also needs to be run on the RMS server, since it will default to the “localhost” value to connect to the SDK service and the user running the command must have sufficient privileges to query the SCOM environment.

Get-RuleParameter -RootManagementServer "RMS01" -Credential $myCred -ClassCriteria "DisplayName like ‘SQL%’" -RuleCriteria "DisplayName like ‘Collect%’" –Verbose

This command will show you all overrideable parameters of all classes, whose display name starts with “SQL” and for all rules whose display name start with “Collect”.  The command will also try to connect to the RMS called “RMS01” and will ask for your credentials to use for connecting to this RMS. And finally it uses the –Verbose switch, to show additional information about the progress of the command.

add-pssnapin mkrOpsMgr

add-pssnapin "Microsoft.EnterpriseManagement.OperationsManager.Client";

set-location "OperationsManagerMonitoring::";

$con = new-managementGroupConnection -ConnectionString:"RMS01" -Credential $myCred;

$mp = get-managementpack | where {$_.Name -eq "mpTestRuleOverride"}

Set-RuleOverride -ManagementPack $mp -ClassCriteria "DisplayName=’SQL 2005 DB’" -RuleCriteria "DisplayName=’Collect Database Free Space (%)’" -Parameter "Enabled" -Value "False" -Verbose –Enforce

These commands will load both the mkrOpsMgr and the Microsoft Operations Manager snapin followed  by a connection to the SDK on the server called “RMS01” (it will ask for credentials). It will retrieve the object for the “mpTestRuleOverride” management pack (which must exist) and will disable the rule with DisplayName “Collect Databse Free Space (%)” form the class with the DisplayName “SQL 2005 DB”. This is done by setting the parameter “Enabled” to “False”. This override is enforced with the –Enforce switch.

add-pssnapin mkrOpsMgr

add-pssnapin "Microsoft.EnterpriseManagement.OperationsManager.Client";

set-location "OperationsManagerMonitoring::";

$con = new-managementGroupConnection -ConnectionString:"RMS01" -Credential $myCred;

$mp = get-managementpack | where {$_.Name -eq "mpTestRuleOverride"}

Set-RuleOverride -RootManagementServer "RMS01" -Credential $myCred -ManagementPack $mp -ClassCriteria "DisplayName=’SQL 2005 DB’" -RuleCriteria "DisplayName=’Collect Database Free Space (%)’" -DataSource "DS" -Parameter "IntervalSeconds" -Value "7777"

These commands will override the rule “Collect Database Free Space (%)” from the class “SQL 2005 DB” and set the value for the “IntervalSeconds” parameter to 7777. Note that running these command a second time, will generate an error indicating there is an override conflict on the rule. You can use the override name shown by the error to change the existing override, using the –OverrideId parameter of the Set-OverrideRule cmdlet.

Running this command the second time on my system, resulted in the error shown below:

: Verification failed with [1] errors:
——————————————————-
Error 1:
: Failed to verify Override [mkrOpsMgr.SetOverrideRule.0888eee2d8754f47820bac3e7887d7d5].
Override [mkrOpsMgr.SetOverrideRule.0888eee2d8754f47820bac3e7887d7d5] is a duplicate to Override [mkrOpsMgr.SetOverrideRule.9415ca506dd540d683c907bbdf1062aa] de
fined within the same ManagementPack. Please remove any one of the duplicate overrides.
——————————————————-

Failed to verify Override [mkrOpsMgr.SetOverrideRule.0888eee2d8754f47820bac3e7887d7d5].Override [mkrOpsMgr.SetOverrideRule.0888eee2d8754f47820bac3e7887d7d5] is
a duplicate to Override [mkrOpsMgr.SetOverrideRule.9415ca506dd540d683c907bbdf1062aa] defined within the same ManagementPack. Please remove any one of the duplic
ate overrides.

The blue OverrideId is the Id generated by the cmdlet when it was run for the second time. The red OverrideId is the existing one in the management pack. If you need to change an existing override, you should supply the existing OverrideId to the cmdlet:

add-pssnapin mkrOpsMgr

add-pssnapin "Microsoft.EnterpriseManagement.OperationsManager.Client";

set-location "OperationsManagerMonitoring::";

$con = new-managementGroupConnection -ConnectionString:"RMS01" -Credential $myCred;

$mp = get-managementpack | where {$_.Name -eq "mpTestRuleOverride"}

Set-RuleOverride -RootManagementServer "RMS01" -Credential $myCred -ManagementPack $mp -ClassCriteria "DisplayName=’SQL 2005 DB’" -RuleCriteria "DisplayName=’Collect Database Free Space (%)’" -DataSource "DS" -Parameter "IntervalSeconds" -Value "8888" -overrideid "mkrOpsMgr.SetOverrideRule.9415ca506dd540d683c907bbdf1062aa"

These commands will now set the same override to the new value of 8888

I now realize I have not implemented a method to remove an override, so a new version will be build 🙂

Posted in management packs, PowerShell | 3 Comments »

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.

Posted in grouping and scoping, management packs | 2 Comments »