Category Archives: Authoring

Create a Group of Health Service Watcher Objects Using VSAE

Plenty of bloggers have written about creating groups of health service watcher objects. The purpose of these types of groups is primarily for notification subscriptions. The reason why we need to include Health Service Watcher objects in our subscription criteria is so recipients also receive notifications about Health Service Heartbeat Failures and Computer Not Reachable alerts.

In this post, I will demonstrate how to create these type of groups using the Visual Studio Authoring Extensions.

In this example, I will create a group of health service watcher objects based on membership of another group (the "source" group). How the source group was created does not matter, as our group of Health Service Watcher objects will always be dynamic in nature and match the source group membership.

Before you start, you’ll need to locate the sealed version of the MP that contains the source group. In this case, I’ll reference a built-in group in the Windows Operating System MP: Windows Server 2012 Computer Group. To figure out which MP the group is stored in, you can run the following command in the Operations Manager Command Shell (replace with your group name).

 Get-SCOMGroup -DisplayName 'Windows Server 2012 Computer Group' | Get-SCOMClass | Select ManagementPackName

 

In this example, the group is stored in the Microsoft.Windows.Server.Library.

1. Create a new Operations Manager 2012 Add-On project in Visual Studio, name it Demo.HealthServiceWatcherGroups, and add a reference to the Microsoft.Windows.Server.Library MP (or the MP containing your source group). Also add a reference to the Microsoft.SystemCenter.InstanceGroup.Library MP – you need to reference this for the discovery relationship.

NOTE: I use fragments heavily in MP authoring, and don’t rely on the templates at all. I think it offers much more flexibility and allows me to retain a library of my own fragments that I can reuse later. This MP will consist of three fragments; one for the MP display name, one for the singleton class (group), and one for the group discovery.

 

2. Add a new empty management pack fragment named mp.DisplayName.mpx, paste the following code into it, and save the fragment. This fragment will provide the MP friendly name.

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <
LanguagePacks>

    <
LanguagePack ID="ENU" IsDefault="true">

      <
DisplayStrings>

        <
DisplayString ElementID="Demo.HealthServiceWatcherGroups">

          <
Name>Demo – Health Service Watcher Groups</Name>

          <
Description>This management pack contains groups of Health Service Watcher objects.</Description>

        </
DisplayString>

      </
DisplayStrings>

    </
LanguagePack>

  </
LanguagePacks>

</
ManagementPackFragment>

3. Add a new empty management pack fragment named class.WindowsServer2012HswGroup.mpx, paste the follow code into it, and save the fragment. This fragment provides the group name and establishes the relationship type. Notice this is a singleton class, which is a group in this case. Also note that I am using default aliases that are generated by VSAE. I choose to use default aliases all the time, so I don’t get confused with custom aliases later. My preference is to store display strings in each  fragment, rather than bunching them all into a single fragment, but you might find other methods that work better for you.

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        <ClassType ID="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroup" Abstract="false" Accessibility="Public" Base="MSIL!Microsoft.SystemCenter.InstanceGroup" Hosted="false" Singleton="true" />
      </ClassTypes>
      <RelationshipTypes>
        <RelationshipType ID="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroupContainmentRelationship" Abstract="false" Accessibility="Public" Base="System!System.Containment">
          <Source ID="Demo.HealthServiceWatcherGroups.Source" Type="System!System.Group" />
          <Target ID="Demo.HealthServiceWatcherGroups.Entity" Type="System!System.Entity" />
        </RelationshipType>
      </RelationshipTypes>
    </EntityTypes>
  </TypeDefinitions>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroup">
          <Name>Demo - Windows Server 2012 Health Service Watcher Group</Name>
          <Description>Contains Health Service Watcher for all instances in the Windows Server 2012 group.</Description>
        </DisplayString>
        <DisplayString ElementID="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroupContainmentRelationship">
          <Name>Windows Server 2012 Health Service Watcher Containment Relationships</Name>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

 

4. Add a new empty management pack fragment named dis.WindowsServer2012HswGroup.mpx, paste the following code into it, and save the fragment. This fragment contains the actual discovery. The module performing the group population is specified in the data source. The main elements you need to be concerned with are highlighted; GroupInstanceId is the group (class) to be populated, MonitoringClass indicates what type of objects to populate the group with, and the expression indicates which source class (or group) to match. Also note MonitoringClass is AgentWatcher. This will populate the group with agents only, not other types of health service’s (like management servers or gateways).

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Monitoring>
    <Discoveries>
      <Discovery ID="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroup.Discovery" ConfirmDelivery="false" Enabled="true" Priority="Normal" Remotable="true" Target="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroup">
        <Category>Discovery</Category>
        <DiscoveryTypes>
          <DiscoveryRelationship TypeID="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities" />
        </DiscoveryTypes>
        <DataSource ID="GroupPop" TypeID="SC!Microsoft.SystemCenter.GroupPopulator">
          <RuleId>$MPElement$</RuleId>
          <GroupInstanceId>$MPElement[Name="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroup"]$</GroupInstanceId>
          <MembershipRules>
            <MembershipRule>
              <MonitoringClass>$MPElement[Name="SC!Microsoft.SystemCenter.AgentWatcher"]$</MonitoringClass>
              <RelationshipClass>$MPElement[Name="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroupContainmentRelationship"]$</RelationshipClass>
              <Expression>
                <Contains>
                  <MonitoringClass>$MPElement[Name="SC!Microsoft.SystemCenter.HealthService"]$</MonitoringClass>
                  <Expression>
                    <Contained>
                      <MonitoringClass>$MPElement[Name="MWSL!Microsoft.Windows.Server.6.2.ComputerGroup"]$</MonitoringClass>
                    </Contained>
                  </Expression>
                </Contains>
              </Expression>
            </MembershipRule>
          </MembershipRules>
        </DataSource>
      </Discovery>
    </Discoveries>
  </Monitoring>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="Demo.HealthServiceWatcherGroups.WindowsServer2012HswGroup.Discovery">
          <Name>Demo - Windows Server 2012 HSW Group Discovery</Name>
          <Description>Populates Demo - Windows Server 2012 HSW Group</Description>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

 

Sign, seal, and import the MP to see the end result.

 

Source group contains a mix of computer objects – both agents and management servers.

image

 

The new group contains health service watcher instances for agents running on Windows Server 2012.

image

 

I plan to post more on creating groups using the Visual Studio Authoring Extensions in the future, so check back or subscribe to the RSS feed.

If you are still using the R2 Authoring Console, I have those examples posted here.

How to create a computer group in the R2 Authoring Console
How to create an instance group in the R2 Authoring Console
How to create a group of Windows Computers based on a discovered property of virtually any class

Starting a Fragment Library using Visual Studio Authoring Extensions

Started using Visual Studio Authoring Extensions recently for all MP authoring, and leaving the Authoring Console behind since it is no longer supported.

I still can’t get used to the templates that are included with VSAE, so I like to create empty management pack fragments. I do this in order to create a library of fragments that I can easily add to management packs in the future.

In this example, I will demonstrate how to start a fragment library by adding a powershell write action that will be used in a scheduled powershell rule.

Create a new Operations Manager 2012 add-on project and add a couple folders to the solution: modules and rules. Then create a new item in the modules folder.

image

Add a new empty management pack fragment.

image

Give it a logical name, like Powershell Write Action, and enter code similar to the following.

 

<ManagementPackFragment SchemaVersion=”2.0″ xmlns:xsd=”http://www.w3.org/2001/XMLSchema”>
<TypeDefinitions>
<ModuleTypes>
<WriteActionModuleType ID=”YourMp.YourPowershellWriteAction” Accessibility=”Internal” Batching=”true”>
<Configuration>
<xsd:element minOccurs=”1″ name=”TimeoutSeconds” type=”xsd:integer” />
<xsd:element minOccurs=”1″ name=”YourScriptParamter1″ type=”xsd:string” />
<xsd:element minOccurs=”1″ name=”YourScriptParamter2″ type=”xsd:string” />
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID=”TimeoutSeconds” Selector=”$Config/TimeoutSeconds$” ParameterType=”int” />
<OverrideableParameter ID=”YourScriptParamter1″ Selector=”$Config/YourScriptParamter1$” ParameterType=”string” />
<OverrideableParameter ID=”YourScriptParamter2″ Selector=”$Config/YourScriptParamter2$” ParameterType=”string” />
</OverrideableParameters>
<ModuleImplementation>
<Composite>
<MemberModules>
<WriteAction ID=”WA” TypeID=”Windows!Microsoft.Windows.PowerShellWriteAction”>
<ScriptName>ScriptName.ps1</ScriptName>
<ScriptBody>
<![CDATA[
Param(
[string]$YourScriptParamter1,
[string]$YourScriptParamter2
)
Do stuff
]]>
</ScriptBody>
<Parameters>
<Parameter>
<Name>YourScriptParamter1</Name>
<Value>$Config/YourScriptParamter1$</Value>
</Parameter>
<Parameter>
<Name>YourScriptParamter2</Name>
<Value>$Config/YourScriptParamter2$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</WriteAction>
</MemberModules>
<Composition>
<Node ID=”WA” />
</Composition>
</Composite>
</ModuleImplementation>
<InputType>System!System.BaseData</InputType>
</WriteActionModuleType>
</ModuleTypes>
</TypeDefinitions>
</ManagementPackFragment>

Of course, add you script in the script body section. This is an example that will pass in two parameters to the script.

Now add another new empty management pack fragment to the rules folder, and enter code similar to the following.

<ManagementPackFragment SchemaVersion=”2.0″ xmlns:xsd=”http://www.w3.org/2001/XMLSchema”>
<Monitoring>
<Rules>
<Rule ID=”YourMp.YourPowershellRule” Enabled=”true” Target=”YourMp.YourClass” ConfirmDelivery=”true” Remotable=”true” Priority=”Normal” DiscardLevel=”100″>
<Category>Operations</Category>
<DataSources>
<DataSource ID=”Schedule” TypeID=”System!System.SimpleScheduler”>
<IntervalSeconds>600</IntervalSeconds>
<SyncTime />
</DataSource>
</DataSources>
<WriteActions>
<WriteAction ID=”WA” TypeID=”YourMp.YourPowershellWriteAction”>
<TimeoutSeconds>300</TimeoutSeconds>
<YourScriptParamter1>first parameter to pass into script</YourScriptParamter1>
<YourScriptParamter2>second parameter to pass into script</YourScriptParamter2>
</WriteAction>
</WriteActions>
</Rule>
</Rules>
</Monitoring>
</ManagementPackFragment>

This rule uses a scheduler as a data source and your new powershell write action module. Remember to fill in the script paramter elements after the script body – this is how the parameter are actually passed into the script.

If you continue saving new fragments to this library project, you can easily add these to your management pack projects in the future by adding an existing item and navigating to your library project.

This is your starter fragment library.

image

Detected malicious verification code when verifying element

Quick post here. Hopefully you find this before spending an hour on it like I did. It ended up being a typo in a write action type id.

Basically, it simply came down to changing this:

<WriteAction ID=”WA” TypeID=”MyMp.MyWriteActin”>

To this:

<WriteAction ID=”WA” TypeID=”MyMp.MyWriteAction”>

Lesson learned – be careful when authoring XML directly and use intellisense when it’s available.

 

Below is the full error I receive by the Visual Studio Authoring Extensions.

Error    72    Detected malicious verification code when verifying element of type Microsoft.EnterpriseManagement.Configuration.ManagementPackRule with inner exception: System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at Microsoft.EnterpriseManagement.Configuration.ManagementPackRule.VerifyDataTypes(Dictionary`2 moduletypes)
at Microsoft.EnterpriseManagement.Configuration.ManagementPackRule.Verify(VerificationContext context)
at Microsoft.EnterpriseManagement.Configuration.Verification.VerificationEngine.VerifyCollectionItems(Object context)   (Path = DR.DiscoveryAutomation)    Management Pack Display Name.mpx    11    10    Discovery Automation

SCOM–seal a management pack

Sealing a Management Pack is easy. Although, it can be frustrating the first time through. It’s a process that requires a few different pieces to interact, so preparation is key. Going through some simple steps now will save time in the future.

  • Create a directory somewhere on a workstation where you’ll be sealing MP’s. For this example, I created the directory c:\MPS
  • I also created four directories within c:\MPS
    • \Input – this directory will contain the MP to be sealed (the xml file)
    • \Output – this directory will contain the sealed MP (the final mp file)
    • \MP – this directory will contain all referenced MP’s
    • \Key – this directory will contain the pair key file
  • Copy MPSeal.exe from the installation media “SupportTools” directory to the c:\MPS directory.
  • Copy sn.exe to the c:\MPS directory
  • Copy your unsealed MP (xml file) into the \Input directory
  • Copy all the *.mp files from the RMS installation directory into the \MP directory
    • Usually “%Program Files%\System Center Operations Manager 2007\”
  • Also, copy all *.mp files that you’ll be referencing to the \MP directory
    • TIP: I’d just keep this directory updated with all available current MP’s (ie; Active Directory, Exchange, etc)

Finally, the c:\MPS directory will look like this.

image

The two files highlighted:
Command.txt is just a file I created that contains the commands needed to seal the management pack. The MPResources.resources file is automatically created while sealing management packs. This is not anything you’ll need to copy into the directory.

Now, we’re ready to seal our Management Pack.

Open a command prompt and navigate to your work directory (c:\MPS). Run these commands in sequence. (beware of word wrap with these commands)

  • sn -k c:\mps\key\PairKey.snk
  • sn -p c:\mps\key\PairKey.snk c:\mps\key\PubKey
  • sn -tp c:\mps\key\PubKey
  • mpseal c:\mps\input\unsealed_mp.xml /I “c:\mps\mp” /Keyfile “c:\mps\key\PairKey.snk” /Company “Your Company” /Outdir “c:\mps\output”

You should now have your sealed MP in the Output directory. And, you’ll have a working directory for later use. Just remember to keep the MP versions in the c:\MPS\MP directory current with your Management Groups. Otherwise, you’ll get version errors while attempting to run the MPSeal tool.

Hint: Once you’ve created the key the first time around, it’s not necessary to create a new key each time you seal a MP. The current key may be reused. So, the only step you’ll need to actually do after the first run is the last step. How’s that for easy!

A note to developers: I’ve had some questions about where the MPResources.resources file mentioned above is created. Specifically, if two build flavor threads (x64 and x86, for example), compiles at same time and try to create this file under sources, one build thread will break.

To solve that problem, execute MPSeal from a different location. Examples below.

This will create the MPResources.resources file in the users %temp% directory.clip_image002

This will create the MPResources.resources file in the x86 directory I created.clip_image004

This will create the MPResources.resources file in the x64 directory I created.clip_image006