Visual Studio Authoring Extensions - Example Management Pack

The purpose of this demo is to create a quick and simple management pack with some custom elements, so you can get an idea of how to use the simple and advanced templates, and how to handle situations for which templates don’t exist yet.

This demo is known as “Network Speed.” Its goal is to measure the speed on your network by copying a file and determining how long that process takes. If you want to test this MP in your own environment, you’ll need a file called test2.txt located at \srv02\share\test2.txt, or else you’ll need to adjust the configuration depending on the location of your file.

Creating the Management Pack

From the Visual Studio Start Page, click the New Project link. In the New Project dialog box, select Operations Manager Core Monitoring Management Pack. Name the Project Network Speed, and click OK. Visual Studio creates the project and opens a blank window.

References

First, you need to add two references, because this MP refers to elements that aren’t part of the default reference configuration in VSAE. Right-click on the References folder and select Add Reference. The Add References dialog box opens. Click the Browse tab and then navigate to where the MPs are stored on your system (by default C:\Program Files (x86)\Visual Studio Authoring Console\References\OM2007R2). The two libraries you’ll need to add are:

  • Microsoft.SytemCenter.DataWarehouse.Library
  • System.Performance.Library

You need to add each one separately.

Class

You only need one class for this demo, a class to provide a target for the sample rules and monitors. To create a new class: Right-click on the solution, select Add → New Item, and then select Class from the Add New Item dialog box. Name the class TargetClass and click Add. An XML editing window appears with some skeleton XML for defining a class. Change the sample <ClassType> entity to the following:

<ClassType ID="Network_Speed.TargetClass" Base="Windows!Microsoft.Windows.LocalApplication" Accessibility="Internal" Abstract="false" Hosted="true" Singleton="false">

In the LanguagePacks section, change the <DisplayString> element to the following:

<DisplayString ElementID="Network_Speed.TargetClass">
<Name>Network Speed Target Class</Name>
<Description>Class to act as a target for sample rules and monitors.</Description>
</DisplayString>

That’s all you need to define the class. Save the file.

Custom Modules

The discovery, monitor, and rule used in this example use a custom data source, which itself uses a custom probe action module. The data source has interval and sync time parameters. The probe action module runs a PowerShell script that streams a text file on the network and measures how long the process took. The only parameter to the PowerShell script is the name of the file, which you can change if you don’t have the test2.txt file on your network.

Custom modules do not have a template available at this time; therefore, you need to create a management pack fragment to hold them. Right-click on the solution, select Add → New Item, and then select Empty Management Pack Fragment. Name the file Modules, and click Add. An XML editing window appears, but this time there’s no skeleton, aside from the <MangementPackFragment> tags. Add the following XML between those two tags:

<TypeDefinitions>
<ModuleTypes>
<DataSourceModuleType ID="Network_Speed.NetworkSpeedScheduled" Accessibility="Public">
<Configuration>
<xsd:element minOccurs="1" name="Interval" type="xsd:integer" />
<xsd:element minOccurs="0" name="SyncTime" type="xsd:string" />
<xsd:element minOccurs="1" name="File" type="xsd:string" />
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="Interval" Selector="$Config/Interval$" ParameterType="int" />
<OverrideableParameter ID="SyncTime" Selector="$Config/SyncTime$" ParameterType="string" />
<OverrideableParameter ID="File" Selector="$Config/File$" ParameterType="string" />
</OverrideableParameters>
<ModuleImplementation>
<Composite>
<MemberModules>
<DataSource ID="Scheduler" TypeID="System!System.Scheduler">
<Scheduler>
<SimpleReccuringSchedule>
<Interval>$Config/Interval$</Interval>
<SyncTime>$Config/SyncTime$</SyncTime>
</SimpleReccuringSchedule>
<ExcludeDates />
</Scheduler>
</DataSource>
<ProbeAction ID="Script" TypeID="Network_Speed.NetworkSpeed">
<File>$Config/File$</File>
</ProbeAction>
</MemberModules>
<Composition>
<Node ID="Script">
<Node ID ="Scheduler" />
</Node>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>Perf!System.Performance.Data</OutputType>
</DataSourceModuleType>
<ProbeActionModuleType ID="Network_Speed.NetworkSpeed" Accessibility="Internal" Batching="false" PassThrough="false">
<Configuration>
<xsd:element minOccurs="1" name="File" type="xsd:string" />
</Configuration>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<ProbeAction ID="Script" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagProbe">
<ScriptName>NetworkSpeed.ps1</ScriptName>
<ScriptBody>
<![CDATA[
param($fileToRead)

$startTime = [DateTime]::Now
$streamReader = new-object System.IO.StreamReader($fileToRead)
$value = $streamReader.ReadToEnd()
$endTime = [DateTime]::Now
$timeInSeconds = $endTime.Subtract($startTime).TotalSeconds
$api = new-object -comObject "MOM.ScriptAPI"
$api.LogScriptEvent('NetworkSpeed.ps1',200,4,$timeInSeconds)
$bag = $api.CreatePropertyBag()
$bag.AddValue("TimeInSeconds",$timeInSeconds)
$bag
]]>
</ScriptBody>
<Parameters>
<Parameter>
<Name>FileToRead</Name>
<Value>$Config/File$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>300</TimeoutSeconds>
</ProbeAction>
<ConditionDetection ID="MapToPerf" TypeID="Perf!System.Performance.DataGenericMapper">
<ObjectName>Network</ObjectName>
<CounterName>FileCopyTime</CounterName>
<InstanceName>$Config/File$</InstanceName>
<Value>$Data/Property[@Name='TimeInSeconds']$</Value>
</ConditionDetection>
</MemberModules>
<Composition>
<Node ID="MapToPerf">
<Node ID="Script" />
</Node>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>Perf!System.Performance.Data</OutputType>
<InputType>System!System.BaseData</InputType>
</ProbeActionModuleType>
</ModuleTypes>
</TypeDefinitions>

Save the file. Now this data source module, with an ID of NetworkSpeedScheduled, is available anywhere you need to use it.

Discovery

Now add the Discovery. Right-click on the solution, select Add → New Item, and then select Discovery. Name the file Discovery, and click Add. This time, you won’t see an XML window; Visual Studio creates a template group and places a discovery item in the list. It should be the only item in the list in the main window, with a name of NewDiscovery. Click on that item so that the properties for the discovery show up in the Properties window, which is where you’ll edit them.

Leave the settings in the “Advanced” section at their defaults (Confirm Delivery, Priority, Remotable).

In the Discovery Types section, click the Discovery Classes item, then click the ellipsis (…) button in the right column. This opens the Discovery Classes Collection Editor.

If you were discovering more than one class, you could enter multiple classes here. However, you’re only discovering the one class, so this will be quick. Click the Add button on the right to add a new class to the collection, which adds a couple of rows to the right pane. You want to add the class you just created, so in the right pane, click the Class item, then click the ellipsis (…) button. A dialog box opens with a list of the available classes. This list includes all classes in management packs to which this management pack has a reference, as well as any classes created in the current MP. Select the class you just created (which is why you created the class first), and click OK.

You can now edit any class properties you need for the discovery; for example, you may want the discovery to only discover certain instances of the class based on its properties. That’s not the case here, so leave the Class Properties alone and click OK. The Discovery Classes field will still show (Collection), but don’t worry about that; you’ve entered the class. You can always click on it again to check if you want.

There are no relationships to go with this discovery, so leave the Discovery Relationships field alone.

In the next section, General, most of the items can be left at their defaults, but not all of them. Leave the Category set to Discovery. Add a comment and a description if you like. The Description will show up in the Operations Console; the Comment will not. Provide a Display Name for the discovery; this will show up in the Operations Console. Leave Enabled set to True. Add an ID for the discovery, such as “TargetDiscovery”; this ID will be used internally. You don’t have to enter the entire name; just enter the name of this discovery element, and the project’s MP namespace will be added to the front of it.

The Target field is the most important in this section. When you click the ellipsis (…) button in that row, you’ll see the Class picker window again. You need to select the object that you will target for the discovery; that is, the target class contains the class that the discovery is looking for. In this case, select Windows!Microsoft.Windows.Computer, because that’s where the target class lives.

In the Modules section, you have to create and configure the data source module for this discovery. First, you need to set the Data Source Type ID, because the configuration field won’t work until you do. Click the Data Source Type ID field, and then click the ellipsis (…) button. A dialog box appears, similar to the Class picker, where you can choose a Data Source Module Type. For this demo, select Microsoft.Windows.FilteredRegistryDiscoveryProvider. Click OK when you’re done.

The Data Source Comment is optional. The Data Source Run As row is only needed if you need the discovery to run under a different account than the default action account, so leave it blank. The Data Source ID is already filled in with a value of “DS,” which is commonplace, so leave that. Finally, click the Data Source Configuration field, and then click the ellipsis (…) button. A small XML editing window opens, where you can enter the configuration for the data source. In this case, enter the following XML between the <Configuration> tags:

<ComputerName>$Target/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$</ComputerName>
<RegistryAttributeDefinitions>
<RegistryAttributeDefinition>
<AttributeName>AppExists</AttributeName>
<Path>SOFTWARE\MPAuthor\CustomDataSource</Path>
<PathType>0</PathType>
<AttributeType>0</AttributeType>
</RegistryAttributeDefinition>
</RegistryAttributeDefinitions>
<Frequency>120</Frequency>
<ClassId>$MPElement[Name="Network_Speed.TargetClass"]$</ClassId>
<InstanceSettings>
<Settings>
<Setting>
<Name>$MPElement[Name="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Name>
<Value>$Target/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="System!System.Entity"]/DisplayName$</Name>
<Value>$Target/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value>
</Setting>
</Settings>
</InstanceSettings>
<Expression>
<SimpleExpression>
<ValueExpression>
<XPathQuery Type="String">Values/AppExists</XPathQuery>
</ValueExpression>
<Operator>Equal</Operator>
<ValueExpression>
<Value Type="String">True</Value>
</ValueExpression>
</SimpleExpression>
</Expression>

That completes the discovery. Save the project before continuing.

Monitors

Next you��ll create a monitor. This demo uses a custom monitor type, and you’ll need to create that before you can create the unit monitor. There is no template for a monitor type at this time, so you’ll need to create this monitor type in an MP fragment. Right-click the project, select Add → New Item, and select Empty Management Pack Fragment. Name it MonitorTypes and click Add. As with the data source, the XML window that appears will be mostly empty. Add the following Monitor Type Definition:

<TypeDefinitions>
<MonitorTypes>
<UnitMonitorType ID="Network_Speed.MonitorType.NetworkSpeed" Accessibility="Public">
<MonitorTypeStates>
<MonitorTypeState ID="UnderThreshold" NoDetection="false" />
<MonitorTypeState ID="OverThreshold" NoDetection="false" />
</MonitorTypeStates>
<Configuration>
<xsd:element minOccurs="1" name="Interval" type="xsd:integer" />
<xsd:element minOccurs="1" name="File" type="xsd:string" />
<xsd:element minOccurs="1" name="Threshold" type="xsd:double" />
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="Interval" Selector="$Config/Interval$" ParameterType="int" />
<OverrideableParameter ID="File" Selector="$Config/File$" ParameterType="string" />
<OverrideableParameter ID="Threshold" Selector="$Config/Threshold$" ParameterType="double" />
</OverrideableParameters>
<MonitorImplementation>
<MemberModules>
<DataSource ID="DS" TypeID="Network_Speed.NetworkSpeedScheduled">
<Interval>$Config/Interval$</Interval>
<File>$Config/File$</File>
</DataSource>
<ProbeAction ID="Probe" TypeID="Network_Speed.NetworkSpeed">
<File>$Config/File$</File>
</ProbeAction>
<ProbeAction ID="PassThrough" TypeID="System!System.PassThroughProbe" />
<ConditionDetection ID="FilterOverThreshold" TypeID="System!System.ExpressionFilter">
<Expression>
<SimpleExpression>
<ValueExpression>
<XPathQuery Type="Double">Value</XPathQuery>
</ValueExpression>
<Operator>GreaterEqual</Operator>
<ValueExpression>
<Value Type="Double">$Config/Threshold$</Value>
</ValueExpression>
</SimpleExpression>
</Expression>
</ConditionDetection>
<ConditionDetection ID="FilterUnderThreshold" TypeID="System!System.ExpressionFilter">
<Expression>
<SimpleExpression>
<ValueExpression>
<XPathQuery Type="Double">Value</XPathQuery>
</ValueExpression>
<Operator>Less</Operator>
<ValueExpression>
<Value Type="Double">$Config/Threshold$</Value>
</ValueExpression>
</SimpleExpression>
</Expression>
</ConditionDetection>
</MemberModules>
<RegularDetections>
<RegularDetection MonitorTypeStateID="UnderThreshold">
<Node ID="FilterUnderThreshold">
<Node ID="DS" />
</Node>
</RegularDetection>
<RegularDetection MonitorTypeStateID="OverThreshold">
<Node ID="FilterOverThreshold">
<Node ID="DS" />
</Node>
</RegularDetection>
</RegularDetections>
<OnDemandDetections>
<OnDemandDetection MonitorTypeStateID="UnderThreshold">
<Node ID="FilterUnderThreshold">
<Node ID="Probe">
<Node ID="PassThrough" />
</Node>
</Node>
</OnDemandDetection>
<OnDemandDetection MonitorTypeStateID="OverThreshold">
<Node ID="FilterOverThreshold">
<Node ID="Probe">
<Node ID="PassThrough" />
</Node>
</Node>
</OnDemandDetection>
</OnDemandDetections>
</MonitorImplementation>
</UnitMonitorType>
</MonitorTypes>
</TypeDefinitions>

With the UnitMonitorType created, you can now go ahead and create the monitor from that type. Right-click the project, select Add → New Item, and select Monitor (Unit). Name the fragment UnitMonitor, and click Add. Like the discovery, the unit monitor is created in a template group that contains one item, labeled NewUnitMonitor. Select it, and edit its properties in the Properties window.

Leave the Advanced properties (Confirm Delivery, Monitor Run As, Priority, and Remotable) at their defaults.

For the Alert settings:

  • Alert Auto Resolve: Set to True.
  • Alert Description: Click the ellipsis button. A new window opens asking you to enter an alert description. You can’t edit this right in the Properties window, because the alert description can have variables and carriage returns. You don’t need that for this example, however.
  • Alert Name: Enter a name for this alert.
  • Alert On State: Change to Error.
  • Alert Priority: Leave this set to Normal.
  • Alert Severity: Leave this set to Error.

For the General settings:

  • Accessibility: Set this to Public
  • Category: Set this to PerformanceHealth
  • Comment: Enter a comment for this monitor (optional). This description won’t appear in the UI.
  • Description: Enter a description for this monitor. This description does appear in the UI.
  • Display Name: Enter a name for this monitor, which will appear in the UI.
  • Enabled: Set this to true
  • ID: Enter “Monitor.NetworkSpeed” here. This is the ID for this monitor, which will be prefaced by the MP namespace.
  • Target: The target class for the monitor. Click the … button, and the Choose a Class dialog box appears. This box has a list of all the available target classes for this monitor, in this MP and all the referenced MPs. Select the Target class that you created earlier in the demo.

For the Unit Monitor settings, you have to select the Monitor Type ID first, before anything else, or else you’ll get an error. Select the Monitor Type ID entry, and click the … button. You’ll see another dialog box, similar to the Target dialog box, with the available unit monitor types. That’s why you needed to create the unit monitor type before creating the monitor itself. Select the NetworkSpeed monitor type that you already created.

Monitor Configuration: Select this line, click the … button, and an XML editing window appears. Here, you enter the specific configuration for this monitor. In this case, enter the following between the <configuration> tags:

<Interval>120</Interval>
<File>\\srv02\share\test2.txt</File>
<Threshold>1</Threshold>

Click OK when you’re done.

Monitor Operational States: Select this line, click the … button and a monitor conditions dialog box appears. For a two-state monitor, as in this example, you’ll see two states (under threshold and over threshold). For a three-state monitor, you’ll see three states. By default, both states will have a health state of Critical (red), so you must change at least one of them to have a useful monitor. In this case, click the UnderThreshold state, and change it from Critical to Healthy. You can also double-click in the Operational State column to change the IDs of the operational states, but that’s not necessary for this example. Click OK when you’re done.

Parent Monitor ID: Select the monitor that this unit monitor would roll up to. In this case, select System.Health.PerformanceState.

You have now successfully created and configured the unit monitor.

Rules

Next you need to create a rule to collect the performance data. Right-click the project, and select Add → New Item. When the Add New Item dialog box appears, you’ll see that there are four types of rules that can be created: Rule (Alert), Rule (Custom), Rule (Event Collection), and Rule (Performance Collection). Each one uses a slightly different template. In this example, you need a performance collection rule, so select that, name it CollectionRule, and click Add. The Template collection appears, with the NewPerformanceCollectionRule selected. Fill in the properties as follows:

In the Advanced properties section:

  • Confirm Delivery: Leave this set to False
  • Discard Level: Leave this set to 100
  • Priority: Leave this set to Normal
  • Remotable: Leave this set to True

In the Collection properties section, these properties indicate whether the data collected by the rule should be written to the Operations Manager database (for use in views), or to the Operations Manager Data Warehouse (for use in reports). Leave these both at their default of True.

In the General section, make the following settings:

  • Category: Leave this at the default of PerformanceCollection
  • Comment: Enter an optional comment about what the rule does; this text does not appear in the UI.
  • Description: Enter a description for the rule; this text does appear in the UI.
  • Display Name: The name for the rule that will appear in the UI. Set this to “Collect network speed”.
  • Enabled: Leave this set to True
  • ID: The unique identifier for the rule within the MP. Again, this will be prefaced with the MP namespace. Set this to “CollectNetworkSpeed”.
  • Target: Clicking on this line opens a dialog box with the available target classes for the rule. Select the Target class you created earlier in the demo.

The Modules section is the most involved section, for a rule. Here you’ll configure the data source module and condition detection module for the rule. If you need to create custom modules, remember that there is currently no template for custom modules; you’ll need to create them first as fragments and refer to them from the appropriate properties.

This example doesn’t use any condition detection module, so leave those elements as they are.

Before you can enter any configuration for the data source module, you’ll need to enter the Data Source Type ID; otherwise, you’ll get an error when you try to enter the configuration. Click the Data Source Type ID row, and click the … button to produce a list of data source types defined in the referenced management packs, including the one you created earlier. Select it and click OK.

Now you can enter the configuration. Click Data Source Configuration, and click the … button. The XML editing window opens. Between the <Configuration> tags, enter the following XML:

<Interval>120</Interval>
<SyncTime />
<File>\\srv02\share\test2.txt</File>

Click OK when you’re done.

That’s all the configuration that the rule requires. Save the project.

Presentation

This demo doesn’t have a lot of presentation, but there is a view and a folder that contains it for use in the Operations Console. To add those, right-click the project, select Add → New Item, and select Folder & Folder Item from the dialog box. Name it ViewFolder and click Add. This is a simple template, so you’re taken to an XML editing window, where most of what you need is already added for you. The <Folders> element is fine the way it is, so feel free to leave that alone. Remove the comment tags around the <FolderItem> element, and change the content of that tag to the following:

<FolderItem ElementID="Network_Speed.View.TargetClass" Folder="Network_Speed.ViewFolder" />

In the <DisplayStrings> section, find the <DisplayString> element for the folder, and give it a more descriptive name.

Now you need to create the view to go in the folder, so right-click the project, select Add → New Item, and select View (Custom) in the dialog box. Name the fragment TargetView and click Add.

The View template is an Advanced template, so select the NewView item and edit the properties in the Properties window. Leave the Accessibility set to Internal. Change the Category to StateCollection. Add a descriptive comment or description if you like. Change the Display Name to “Target View” and the ID to “TargetView”. Click the Target Row, and then click the ellipsis (…) button. When the class picker dialog box appears, select the class you defined for this project.

In the View section, again, start with the type. Click the View Type ID row and then click the ellipsis (…) button. In the type picker, select Microsoft.SystemCenter.StateViewType and click OK. Click the View Folder row, click the ellipsis, and in the folder picker, select the folder you created above and click OK. There’s no

That’s all you need for the presentation section. Save the file.

Deployment

Before you can deploy the project, take a look at the project properties: right-click the project and select Properties to open the Properties window for this project. The Management Pack tab shows basic naming information for this MP. You shouldn’t need to make any changes here, but you may if you wish. Click the Build tab. If you want to seal the management pack, check the “Generate sealed and signed management pack” box on this tab. You’ll need to have a key file if you want to seal the MP. Click the Management Group tab. If you want to deploy the MP to a management group immediately, click Add and add your management group here. Finally, click Deployment. In the Start Action section, you can select whether to deploy the project to the management group automatically, and whether to start the Operations Console or the web console.

Once you’ve set the deployment options, select Build → Build Solution, or press F5. You should see an output window listing the various verification methods used on your project, and if all went well, a success message at the end. If there’s a problem with the project, a list of errors and warnings will appear instead. You can ignore the informational items, but you must resolve the errors before the MP will build. You’ll usually have to scroll to the end of the list to find the errors. Double-click on the error to be taken to the spot in the code where the error is found, although that may not necessarily be the right place to fix the error. For example, if you have two elements with the same name in the management pack, clicking the error will only take you to one instance; you may need to change the other.

After you’ve resolved the errors, you can rebuild the project by selecting Build → Build Solution, or pressing F5 again. If you chose to deploy the management pack automatically, you should see it in the Operations Console. If you didn’t, you can find the finished management pack in the /bin/Debug or /bin/Release folder for the project, depending on the configuration you selected on the Build tab. The default location for this project is:

C:\Users\username>\Documents\Visual Studio 2010\Projects\Network Speed\Network Speed\bin\Debug

The management pack is now complete, and ready to use.

Additional Resources

[[Visual Studio Authoring Extensions for System Center 2012 - Operations Manager]]

[[Visual Studio Authoring Extensions - Visual Studio Features]]

[[Visual Studio Authoring Extensions - Simple Templates]]

[[Visual Studio Authoring Extensions - Advanced Templates]]