PowerShell and the Service Manager Type Environment   Leave a comment

Service Manager, like Operations Manager, has a dynamic type system.  ManagementPacks define types, called classes, which define the actual data that you want to keep track of.  You declare a class which may or may not be based on another class and you can add properties to your class, and manipulate it in a number of ways.  Once you’ve imported your management pack, you’ll have access to that new class, and can create instances of that class.  There are two discrete categorizations of types.  The first is a simple class, and the more complex is called a type projection.  In this blog, we’ll discuss how to find out what Service Manager stores as simple classes and how to discover them.

It’s important to note that these are not .NET types, these are types as defined in the Service Manager environment.  When you actually create instances of these types, they are returned as instances of the .NET type of Microsoft.EnterpriseManagement.Common.EnterpriseManagementObject.  That object has a property called PropertyCollection which is where the actual data is held.  I’ll talk more about that in a future blog, but for now, what you should know is that Service Manager has it’s own types which are created in Management Packs.

To get access to the list of classes that have been imported to the Service Manager environment, we’ll use the EnterpriseManagementGroup object again (see my previous posts).  The EnterpriseManagementGroup object has an interface named "EntityTypes", which has a number of methods that we’ll investigate.  First, we’ll create an EnterpriseManagementGroup, and take a look at the EntityTypes interface.

PS> $EMG = new-object Microsoft.EnterpriseManagement.EnterpriseManagementGroup localhost
PS> $EMG.EntityTypes|get-member

   TypeName: Microsoft.EnterpriseManagement.EntityTypeManagement

Name                       MemberType Definition
----                       ---------- ----------
Equals                     Method     bool Equals(System.Object obj)
GetCategories              Method     System.Collections.Generic.IList[Micro...
GetCategory                Method     Microsoft.EnterpriseManagement.Configu...
GetCategoryList            Method     System.Collections.Generic.List[Micros...
GetChildEnumerations       Method     System.Collections.Generic.IList[Micro...
GetClass                   Method     Microsoft.EnterpriseManagement.Configu...
GetClasses                 Method     System.Collections.Generic.IList[Micro...
GetClassesList             Method     System.Collections.Generic.List[Micros...
GetEnumeration             Method     Microsoft.EnterpriseManagement.Configu...
GetEnumerationList         Method     System.Collections.Generic.List[Micros...
GetEnumerations            Method     System.Collections.Generic.IList[Micro...
GetHashCode                Method     int GetHashCode()
GetRelationshipClass       Method     Microsoft.EnterpriseManagement.Configu...
GetRelationshipClasses     Method     System.Collections.Generic.IList[Micro...
GetRelationshipClassesList Method     System.Collections.Generic.List[Micros...
GetTopLevelEnumerations    Method     System.Collections.Generic.IList[Micro...
GetType                    Method     type GetType()
GetTypeProjection          Method     Microsoft.EnterpriseManagement.Configu...
GetTypeProjectionList      Method     System.Collections.Generic.List[Micros...
GetTypeProjections         Method     System.Collections.Generic.IList[Micro...
ToString                   Method     string ToString()

The methods break up in two big groups: The first group returns all various different objects that you can define in a management pack (those objects which have to do with types, anyway). That list is:


The other methods on this interface take arguments and return a reduced set of results based on the arguments. It is important to note that the Service Manager environment caches most of this configuration information, so when we get all of them, it doesn’t result in lots of trips to the database. That’s good news from a performance perspective.  From a PowerShell perspective, it means that we can grab all the data and use the PowerShell filtering capabilities rather than bothering with the other available methods.

If we want to see all the different classes that Service Manager knows about, we can do that easily:

PS> $EMG.EntityTypes.GetClasses() 

PropertyCollection     : {DisplayName}
Base                   :
Hosted                 : False
Singleton              : False
Extension              : False
OptimizationCollection : {}
FullTextSearchable     :
XmlTag                 : ClassType
Abstract               : True
Accessibility          : Public
ManagementGroup        : WIN-752HJBSX24M
ManagementGroupId      : 386f5f57-9f7a-3c6b-1f53-ccc02d6206d4
Name                   : System.Entity
Id                     : ac5cddfc-a96a-ee99-745d-ec74845f53f6
DisplayName            : Object
Description            : All objects
LanguageCode           : ENU
Comment                :
Status                 : Unchanged
LastModified           : 5/14/2009 11:56:48 PM
TimeAdded              : 5/14/2009 11:56:48 PM

PropertyCollection     : {}
Base                   : ManagementPackElementUniqueIdentifier=ac5cddfc-a96a-ee
Hosted                 : False
Singleton              : False
Extension              : False
. . .

Wow! There’s a lot here – let’s find out how many:

PS> $Classes = $EMG.EntityTypes.GetClasses()
PS> $Classes.Count 231

We should determine the .NET type as well, as we can use this when we create our formatting instructions

PS> $classes[0].gettype().fullname

With a result as large as this, it makes more sense to see as a table, rather than a list and I’ll select the first 5, just to cut down on space, so now we have:

PS> $Classes|select-object -first 5| format-table Abstract,Name,DisplayName -au
Abstract Name                       DisplayName
-------- ----                       -----------
    True System.Entity              Object
    True System.AdminItem           Admin Item
   False System.Announcement.Config Config
   False System.Announcement.Item   Announcement
    True System.Collections         Collections

We can see that this supports the PowerShell filters as well, let’s find all the types which pertain to printers.  The first approach would be to select only those objects whose name matches print!

PS> $EMG.EntityTypes.GetClasses()|?{$_.name –match "print"}|
>> format-table -auto Abstract,Name,DisplayName

Abstract Name DisplayName
-------- ---- -----------
True System.Printer Printers
False Microsoft.AD.Printer Active Directory Printers

The objects returned work well with the PowerShell environment.  We can invoke the other methods on the EntityTypes interface:

PS> $emg.EntityTypes.GetCategories().Count
PS> $emg.EntityTypes.GetCategories()|select-object -first 5|format-table Name,DisplayName -auto

Name                                                                  DisplayName
----                                                                  -----------

PS> $emg.EntityTypes.GetClasses().Count
PS> $emg.EntityTypes.GetClasses()|select-object -first 5|format-table Name,DisplayName -auto

Name                       DisplayName 
----                       ----------- 
System.Entity              Object      
System.AdminItem           Admin Item  
System.Announcement.Config Config      
System.Announcement.Item   Announcement
System.Collections         Collections 

PS> $emg.EntityTypes.GetEnumerations().Count
PS> $emg.EntityTypes.GetEnumerations()|select-object -first 5|format-table Name,DisplayName -auto

Name                                                        DisplayName          
----                                                        -----------          
ActivityAreaEnum.Messaging.Client                           Client               
ServiceManager.ConfigurationManagement.WindowsPrintersTasks Windows Printer Tasks
IncidentSourceEnum.DCM                                      SCCM (DCM)           
ActivityStageEnum.Develop                                   Develop              

PS> $emg.EntityTypes.GetRelationshipClasses().Count
PS> $emg.EntityTypes.GetRelationshipClasses()|select-object -first 5|format-table Name,DisplayName -auto

Name                                DisplayName                     
----                                -----------                     
System.ComputerPrimaryUser          Computer Primary User           
System.ConfigItemContainsConfigItem Config Item Contains Config Item
System.ConfigItemHasFileAttachment  Config Item Has File Attachment 
System.ConfigItemImpactsCustomers   Config Item Impacts Customers   
System.ConfigItemOwnedByUser        Config Item Owned By User       

PS> $emg.EntityTypes.GetTopLevelEnumerations().Count
PS> $emg.EntityTypes.GetTopLevelEnumerations()|select-object -first 5|format-table Name,DisplayName -auto

Name                                                                          DisplayName         
----                                                                          -----------         
System.Internal.ManagementPack                                                Management Pack     
System.WorkItem.ActionLogEnum                                                 Action Log Enum     
ChangeManagement.CreateTask                                                   Create Task         
Microsoft.EnterpriseManagement.ServiceManager.UI.Authoring.AllObjectTemplates All Object Templates

PS> $emg.EntityTypes.GetTypeProjections().Count
PS> $emg.EntityTypes.GetTypeProjections()|select-object -first 5|format-table Name,DisplayName -auto

Name DisplayName
---- -----------

It looks like we have reasonable output for everything except TypeProjections.  By looking at the count, I can tell that we have some sort of results, so let’s take a closer look at the object:

PS> $emg.EntityTypes.GetTypeProjections()[0]

Key                                     Value
---                                     -----
SyncStatus                              {}

That’s not terribly useful, perhaps get-member will help me.

PS> $emg.EntityTypes.GetTypeProjections()|get-member

   TypeName: Microsoft.EnterpriseManagement.Configuration.ManagementPackTypeProjection

Name                MemberType            Definition
----                ----------            ----------
CreateNavigator     Method                System.Xml.XPath.XPathNavigator Cr...
Equals              Method                bool Equals(System.Object obj)
GetCategories       Method                System.Collections.Generic.IList[M...
GetDisplayString    Method                Microsoft.EnterpriseManagement.Con...
GetEnumerator       Method                System.Collections.Generic.IEnumer...
GetFolders          Method                Microsoft.EnterpriseManagement.Con...
GetHashCode         Method                int GetHashCode()
GetImageReferences  Method                System.Collections.Generic.IEnumer...
GetKnowledgeArticle Method                Microsoft.EnterpriseManagement.Con...
GetManagementPack   Method                Microsoft.EnterpriseManagement.Con...
GetType             Method                type GetType()
Reconnect           Method                System.Void Reconnect(Microsoft.En...
ToString            Method                string ToString()
WriteXml            Method                System.Void WriteXml(System.Xml.Xm...
Item                ParameterizedProperty Microsoft.EnterpriseManagement.ITy...
Accessibility       Property              Microsoft.EnterpriseManagement.Con...
Alias               Property              System.String Alias {get;}
Comment             Property              System.String Comment {get;set;}
ComponentCollection Property              System.Collections.Generic.IList`1...
Description         Property              System.String Description {get;set;}
DisplayName         Property              System.String DisplayName {get;set;}
Id                  Property              System.Guid Id {get;}
LanguageCode        Property              System.String LanguageCode {get;set;}
LastModified        Property              System.DateTime LastModified {get;...
ManagementGroup     Property              Microsoft.EnterpriseManagement.Ent...
ManagementGroupId   Property              System.Guid ManagementGroupId {get;}
Name                Property              System.String Name {get;}
Parent              Property              Microsoft.EnterpriseManagement.ITy...
Status              Property              Microsoft.EnterpriseManagement.Con...
TargetConstraint    Property              Microsoft.EnterpriseManagement.Con...
TargetEndpoint      Property              Microsoft.EnterpriseManagement.Con...
TargetType          Property              Microsoft.EnterpriseManagement.Con...
TimeAdded           Property              System.DateTime TimeAdded {get;set;}
Type                Property              Microsoft.EnterpriseManagement.Con...
TypeProjection      Property              Microsoft.EnterpriseManagement.Con...
XmlTag              Property              System.String XmlTag {get;}

Oho!  it looks like this object has an enumerator.  This means that when PowerShell attempts to format the object, it will call the enumerator and format the enumerated contents (rather than the object).  We can suppress this in PowerShell by specifying the –EXPAND parameter with format-table:

PS> $emg.EntityTypes.GetTypeProjections()|select-object -first 5|
>> format-table -Expand coreonly Name,DisplayName -au

Name                                                          DisplayName
----                                                          -----------
System.NotificationChannel.SMTP.ProjectionType                SMTP Projection Type
System.User.Projection                                        User Projection

That’s better! Although I have a feeling that this really isn’t a good long term solution, perhaps we’ll deal with this in a future posting.

Now that we have a set of these methods we can invoke, it’s a great opportunity to build a PowerShell V2 Module.  We can easily convert these bits of script into functions and aggregate those functions into a module.  All I need to do is put my module (as a .psm1 file) in the right place (see PowerShell V2 documentation on Modules for more help) and call import-module!

Here’s the script file:

$SMDIR = "C:\Program Files\Microsoft System Center\Service Manager 2010"
$SMDLL = "${SMDIR}\SDK Binaries\Microsoft.EnterpriseManagement.Core.dll"
$EMGTYPE = "Microsoft.EnterpriseManagement.EnterpriseManagementGroup"

# Before anything load the Service Manager core dll
[reflection.assembly]::LoadFile( $SMDLL ) | out-null

# Create an EnterpriseManagementGroup object
function New-EMG
   param ( $ComputerName = "localhost" ) 
   new-object $EMGTYPE $ComputerName

# Return the Categories
function Get-SMCategory
    param ( $CategoryName )
    if ( ! $EMG.IsConnected ) { $EMG.Reconnect() }
    $EMG.EntityTypes.GetCategories()|?{$_.Name -match $CategoryName }
# Return the Classes
function Get-SMClass
    param ( $ClassName )
    if ( ! $EMG.IsConnected ) { $EMG.Reconnect() }
    $EMG.EntityTypes.GetClasses()|?{$_.Name -match $ClassName }
# Return the RelationshipClasses
function Get-SMRelationshipClass
    param ( $RelationshipClassName )
    if ( ! $EMG.IsConnected ) { $EMG.Reconnect() }
    $EMG.EntityTypes.GetRelationshipClasses()|?{$_.Name -match $RelationshipClassName }
# Return the TopLevelEnumerations
function Get-SMTopLevelEnumeration
    param ( $TopLevemEnumerationName )
    if ( ! $EMG.IsConnected ) { $EMG.Reconnect() }
    $EMG.EntityTypes.GetTopLevelEnumerations()|?{$_.Name -match $TopLevemEnumerationName }
# Return the TypeProjections
function Get-SMTypeProjection
    param ( $TypeProjetionName )
    if ( ! $EMG.IsConnected ) { $EMG.Reconnect() }
    $EMG.EntityTypes.GetTypeProjections()|?{$_.Name -match $TypeProjetionName }
# We want to have an EMG in our environment!

Notice also that I added a parameter to the functions so I can pass in a string and reduce the result without having to always add my own where-object pipeline.  Notice further that I created a global instance of the EnterpriseManagementGroup, that way I can use it outside of the module.  I’ll use this as the contents for my EntityTypes.PSM1 file and import the module. 

    You should note that this assumes an installation on the Server machine only.  If you want to run these on a machine where only the console is installed, you’ll need to load the SMDLL a little differently.   You would need to do the following instead:


    And you will also need to provide the name of the Service Manager server system when you create your EnterpriseManagementGroup object by calling new-EMG:

    $GLOBAL:EMG = new-EMG servername

On to the module!

PS> get-childitem C:\users\Administrator\Documents\WindowsPowerShell\Modules\EntityTypes

    Directory: C:\users\Administrator\Documents\WindowsPowerShell\Modules\EntityTypes

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         6/19/2009   2:27 PM       1726 EntityTypes.psm1

PS> get-module -list

ModuleType Name                      ExportedCommands
---------- ----                      ----------------
Script     EntityTypes               {}
Manifest   BitsTransfer              {}
Manifest   PSDiagnostics             {}

PS> import-module entitytypes

and we can see that my commands are all present!

PS> get-module entitytypes|fl

Name              : entitytypes
Path              : C:\Users\Administrator\Documents\WindowsPowerShell\Modules\entitytypes\entitytypes.psm1
Description       :
ModuleType        : Script
Version           : 0.0
NestedModules     : {}
ExportedFunctions : {Get-Category, Get-Class, Get-RelationshipClass, Get-TopLevelEnumeration...}
ExportedCmdlets   : {}
ExportedVariables : {}
ExportedAliases   : {}

And I can use them just like a cmdlet:

PS> get-class system.user$|ft abstract,name,displayname -au

Abstract Name        DisplayName
-------- ----        -----------
    True System.User Users

In my next post, I’ll discuss the Service Manager instance space and create cmdlets to use against the actual data that we store in Service Manager.


Posted June 22, 2009 by jtruher3 in ServiceManager

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: