SCOM 2012–Connect to the SDK from PowerShell in an MP

I’ve had a few different scenarios in the past where the need to connect to the SCOM SDK and retrieve data either as part of a monitor or as part of a discovery is necessary.  In most cases, the standard “Import-Module OperationsManager” gets the job done, the SCOM CmdLets are accessible, and whatever workflow I have executing seems to function just fine.  However, recently, I had a customer scenario where this wasn’t working.  The discovery was running on a SCOM management server.  The module was available and functioning outside of a SCOM MP workflow.  For some reason, the Import-Module simply wasn’t working in that specific environment when the PS code was embedded into a management pack.

Troubleshooting wasn’t getting us anywhere so I scanned the existing MPs to see if there was another way that other MPs were loading the OperationsManager module.  I found a few different ways, however, inside of the “Microsoft SystemCenter OperationsManager Summary Dashboard” management pack a connection to the SDK is made like this:

$SCOMPowerShellKey =
“HKLM:\SOFTWARE\Microsoft\System Center Operations Manager\12\Setup\Powershell\V2”
$SCOMModulePath =
Join-Path (Get-ItemProperty $SCOMPowerShellKey).InstallDirectory “OperationsManager”
Import-module $SCOMModulePath

While we didn’t nail down the root cause of the Import-Module failing, this route was successful in connecting to the SDK.

Management Packs, MP Authoring, PowerShell, SC Operations Manager

SCOM 2012–Parameterizing Operators Within MP

In order to create a generic monitor type that is based off a PowerShell DS, you may need to parameterize not only the operators within expression filters but parameterize the name of the name/value pair coming back from the property bag in your PS script.

image

Notice the UnhealthyOperator as well as the HealthyOperator specified within the configuration for the monitor type are of type CriteriaCompareType.  In order to access the type, the ExpressionEvaluatorSchema needs to be included.  Also, notice the Variable configuration element is meant to be the name of the value being passed back from the PS script which needs to be ran through the ExpressionFilter.  The ExpressionFilter is then populated using the $Config variables.  Here is a potential ConditionDetection for a healthy state:

image

Here is the resulting monitor:

image

The monitor would raise an alert if the random number returned from the script is <=5.

Management Packs, MP Authoring, SC Operations Manager, Uncategorized

SCOM 2012 – Reporting Off Operations Console Authored Groups

I was in a situation where I needed to create an availability report based on just a few of my SQL instances.  I quick created a group named “Test SQL Group” and then added a few DB engines into the group specifically:

image

Next, going over to the Availability report in the Generic Report Library, I selected my time frame for the past 24 hours, chose “Add Group”, and selected my group:

image

Fairly straightforward, however, the report comes back blank.  Swapping the group out for a group that already exists inside of SCOM, I run the report for “SQL Instances”.  This brings back availability data for every SQL instance in my lab including the two for which I was looking:

image

This doesn’t make much sense to me so I crack open the MP code and compare the “SQL Instance” group to my “Test SQL Group” I authored through the console:

Test SQL Group

image

SQL Instances

image

Right away, I notice the base class for the group.  In order to get this working quickly, I swap the base type for my custom group out to System.Group and add the reference to my MP.

<Reference Alias=”System”>
<ID>System.Library</ID>
<Version>6.1.7221.0</Version>
<PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
</Reference
>

And

<ClassType ID=”UINameSpace449ec2ec39cb4abdbf5baeec4f518ef1.Group” Accessibility=”Public”
Abstract=”false”
Base=”System!System.Group
Hosted=”false” Singleton=”true” Extension=”false” />

Unfortunately, System.Group is missing a containment relationship that is required in order to make the group function correctly inside of the SCOM console.  That relationship is also the relationship that needs to be used inside of the discovery.

<RelationshipTypes>
<RelationshipType ID=”UINameSpace449ec2ec39cb4abdbf5baeec4f518ef1ContainsDBEngine
Accessibility=”Public” Abstract=”false” Base=”System!System.Containment”>
<Source ID=”Source” MinCardinality=”0″ MaxCardinality=”2147483647″
Type=”UINameSpace449ec2ec39cb4abdbf5baeec4f518ef1.Group” />
<Target ID=”Target” MinCardinality=”0″ MaxCardinality=”2147483647″
Type=”MicrosoftSQLServerLibrary6510!Microsoft.SQLServer.DBEngine” />
</RelationshipType>
</RelationshipTypes>

I have to give the Relationship Type a unique ID and then specify my group (the actual name) for the type.  Once I have this, the discovery needs to be tweaked in order to use the new relationship:

<RelationshipClass>$MPElement[Name=”UINameSpace449ec2ec39cb4abdbf5baeec4f518ef1ContainsDBEngine“]$</RelationshipClass>

I saved, reimported the MP and then tried the report again.  This time, the report works just fine:

image

At this point, I test to make sure this issue isn’t occurring due to the fact that I explicitly added members to a custom group.  Instead, I add the members a new group named “Test SQL Group 2” but this time I use dynamic criteria.  The group has a base class of Microsoft.SystemCenter.InstanceGroup again.  When using this group to run the report, the report comes back blank in this situation as well.

A quick solution to get the Availability report to run based on a custom group is to convert that group to a System.Group rather than leaving it as an instance of Microsoft.SystemCenter.InstanceGroup.

Management Packs, Reporting, SC Operations Manager

SCSM 2012 R2–Adding a Base Enumeration to a Custom WPF Form

Using SC Service Manager 2012 R2 UR2;

I recently had a request from one of my customers to use an existing enumeration from the System.Library management pack within their custom WPF form.  This would mean using the SCSM List Picker control and binding it to the field with the value constraint tied to the enumeration.  This is super straight forward through the SM Authoring Tool, however, when developing a custom form within Visual Studio using WPF, the process is not as simple.

Doing a quick Bing search yields a CodePlex project to use for reference:

http://scsmservicerequest.codeplex.com/

Using this as reference, we can see adding the namespace in for the SC WPF controls is pretty straight forward:

[XAML]

xmlns:smcontrols=”clr-namespace:Microsoft.EnterpriseManagement.UI.WpfControls;
assembly=Microsoft.EnterpriseManagement.UI.SmControls”

You may already have this as part of your project if you already developing a custom form.  If not, add it in and the listpicker control will be available through smcontrols:ListPicker.  Interestingly, the List Picker in this project is also available through the XML namespace scwpf via scwpf:ListPicker through the following:

xmlns:scwpf=”http://schemas.microsoft.com/SystemCenter/Common/UI/Wpf”

They both point at Microsoft.EnterpriseManagement.UI.WpfControls.ListPicker so either is fine.

Here is the code that actually adds the List Picker onto the form from the sample project:

<smcontrols:ListPicker
Grid.Row=”2″
Grid.Column=”1″
Margin=”8,30,8,0″
Name=”lpClassification”
VerticalAlignment=”Top”
ParentCategoryId=”{Binding Source={x:Static
local:ServiceRequest.guidClassificationEnumRoot},
Mode=OneWay}”
SelectedItem=”{Binding Path=Classification,
UpdateSourceTrigger=PropertyChanged,
Mode=TwoWay}”/>

Perfect.  The catch here is that I want to add Object Status to my form and the enumeration is defined in the System.Library management pack.  In the case of the example, an enumeration from the existing project was used and it is accessible through the “local:” namespace.  I could be missing something here, but I was not able to get a namespace added for the System.Library mp.

The ParentCategoryId really just gets set to the GUID of the enumeration that SCSM assigns the type when it gets created.  Something like this will work:

<scwpf:ListPicker Name=”listObjectStatus”
HorizontalAlignment=”Stretch” Width=”Auto”
ParentCategoryId=”{Binding
Source=3dc28152-62a3-bd53-ccc1-66e0ad3df8e8,
Mode=OneWay}”
SelectedItem=”{Binding Path=ObjectStatus, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}” />

In order to get the GUID, I used PowerShell and connected to he SDK for my SCSM environment:

$mp = Get-SCSMManagementPack -name ‘System.Library’
$mp.EntityTypes.GetEnumeration(‘System.ConfigItem.ObjectStatusEnum’,$mp) | Select ID

Id

3dc28152-62a3-bd53-ccc1-66e0ad3df8e8

The GUID should hold constant across management groups so this should be ok…should be ok.  At this point, I really don’t trust that this code will be ok forever and I dislike hardcoding values like this.  It seems that the chance for the GUID to change would definitely exist between environments or maybe as part of an upgrade to a future version.  One would hope not, however, I don’t want to leave it to chance.

Digging further into the CodePlex project, I find this code:

//*** IMPORTANT NOTE: The IManagementGroupSession is not a part of the publicly document/supported official SDK and is subject to change in a future release.
IManagementGroupSession session = (IManagementGroupSession)FrameworkServices.GetService<IManagementGroupSession>();
EnterpriseManagementGroup emg = session.ManagementGroup;

Nice!  It’s the SDK we all know and love.  I poked around a little to see if IManagementGroupSession is documented and supported now.  I didn’t find anything definitive, however, this chunk of code seems to be all over.  In the event that these calls get changed in a future version, the workaround/fix should become available fairly quickly afterwards since it would seem many people/customers would now have a dependency on this code. Thus adding the following as well:

gdObjectStatus =  new Guid();
gdObjectStatus = emg.EntityTypes.GetEnumeration(“System.ConfigItem.ObjectStatusEnum”,
emg.ManagementPacks.GetManagementPack(“System.Library”,
“31bf3856ad364e35”,
new Version(“6.0.5000.0”))).Id;
listObjectStatus.ParentCategoryId = gdObjectStatus;

We end up with the GUID for the System.ConfigItem.ObjectStatusEnum as defined in the System.Library management pack assigned to the ParentCategoryId for the SC WPF List Picker control.  Now, the XAML for the control can be simplified and the GUID can be removed:

<scwpf:ListPicker Name=”listObjectStatus”
HorizontalAlignment=”Stretch”
Width=”Auto”
SelectedItem=”{Binding Path=ObjectStatus,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}” />

Much more simple.  Looking at the custom form, here is the newly added control attached to the Object Status Enum:

image

No more hardcoded GUIDs.  A similar process can be used to get ahold of any GUIDs or objects you want to use on your forms.  Additionally, using the C# code, you can get at any other objects that may in fact not have static GUIDs such as specific instances of a CI or Work Item.

Developement, SC Service Manager

SCOM 2012–’Unspecified error‘ During Class Discovery

Recently, I ran into a situation where my class discovery was not working and all I was getting back was a very generic 0x80004005 error:

image

I turned on a workflow trace, grabbed the ETL and received almost no help whatsoever:

[1]2616.1812::09/04/2014-08:52:02.023 [ModulesLibrary] [] [ModuleDebug] :CModuleHostDebug::NotifyError{ModuleDebug_cpp509}[DiscoveryDataSnapshotMapper] [IModuleHost->NotifyError]  Module reported ModuleErrorSeverityDataLoss    Message: <<Message cannot be displayed>>    Source:  Health Service Modules    Id:  -1073730742    Type: Warning    Category: 0

<<Message cannot be displayed>> is not what I was hoping for from the normally very useful ETL.  The only item I really take from the trace is that the problem is in the [DiscoveryDataSnapshotMapper].  The WMI query in this case actually looks like it returned exactly what I wanted.

Here’s the part of the discovery that would pertain to the mapper:

<ClassId>$MPElement[Name=”CE.TickDemoClass”]$</ClassId>
<InstanceSettings>
<Settings>
<Setting>
<Name>$MPElementName=”WindowsMicrosoft.Windows.Computer”]/PrincipalName$</Name>
<Value>$Target/PropertyType=”WindowsMicrosoft.Windows.Computer”]/PrincipalName$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name=”CE.TickDemoClass”]/DDriveSize$</Name>
<Value>$Data/Property[@Name=’Size’]$</Value>
</Setting>
<Setting>
<Name>$MPElementName=”SystemSystem.Entity”]/DisplayName$</Name>
<Value>$Target/PropertyType=”WindowsMicrosoft.Windows.Computer”]/PrincipalName$</Value>
</Setting>
</Settings>
</InstanceSettings>

Just with a cursory skim, there does not appear to be anything wrong with the code.  The custom class I created for demo purposes is simply a computer role class that gets populated if the machine has D: drive that is a logical disk.  Upon closer review, the value that gets pushed into the DDriveSize attribute is the issue.  At some point, the code was probably copied/pasted from either an advanced editor like Word or possible off the Interwebs.  As such, at some point the single quotes have been converted to “smart quotes”.

Word or other advanced editor Notepad
image image

After spending a few minutes reading on smart vs. dumb quotes on various different sites out there, it made me very thankful that our advanced editors just do in fact take care of much of this for us.  Additionally, it makes me question whether or not I actually retained anything from 7th grade English class.

With that being said, the solution to the discovery is simple.  Replace:

<Value>$Data/Property[@Name=Size]$</Value>

With:

<Value>$Data/Property[@Name=Size]$</Value>

Just one more thing to watch for from a management pack authoring perspective whenever copying and pasting code.

Management Packs, MP Authoring, SC Operations Manager , , , ,