Archive for August 2009

Getting data from Service Manager – a scripted approach   Leave a comment

In one of my earlier posts, I said that you needed some C# to get data from Service Manager because of the way some of our methods use generics. It was pointed out to me that I was wrong, wrong, wrong. So I thought I better post a completely scripted approach for retrieving data from Service Manager.

The following script will return all instances of the class that’s passed as a parameter.

param ( $classname )
$emg      = new-object microsoft.enterprisemanagement.enterprisemanagementgroup localhost
$class    = $emg.EntityTypes.GetClasses()|?{$ -eq $classname}
if ( ! $class )
    Write-Error "`nERROR: Class '$classname' not found, exiting."
$DEFAULT  = [Microsoft.EnterpriseManagement.Common.ObjectQueryOptions]::Default
$EMOT     = [Microsoft.EnterpriseManagement.Common.EnterpriseManagementObject]
# Retrieve the interface for EntityObjects, which we'll use when we create our generic method
$IMGMT    = $emg.EntityObjects.GetType()
# the types of the parameters, this is so we can find the right method
[type[]]$TYPES = [Microsoft.EnterpriseManagement.Configuration.ManagementPackClass],
# Retrieve the method
$ObjectReader = $IMGMT.GetMethod("GetObjectReader",$TYPES)
# Create a generic method
$GenericMethod = $ObjectReader.MakeGenericMethod($EMOT)
# Invoke the method with our arguments
[array]$arguments = [Microsoft.EnterpriseManagement.Configuration.ManagementPackClass]$class,$DEFAULT
$GenericMethod.invoke($emg.EntityObjects,$arguments) | %{
    # Create a custom object based on the original object
    $o = new-object psobject $_
    # elevate the properties in the Values collection to the top level
    $o.values|%{ $o | add-member -force NoteProperty $_.Type $_.Value }
    # assign a synthetic typename to the object, so we can use our formatting
    # more easily
    $name = $_.GetLeastDerivedNonAbstractClass().name
    $o.psobject.typenames.Insert(0, "EnterpriseManagementObject#$name")
    # now, emit the object!

It uses reflection to retrieve the method that I want and then uses that to create a generic method, which can then be invoked with the parameters that I want.  In this case, it’s fairly straightforward, since I want to retrieve all instances of a particular class, I use the overload of GetObjectReader which takes a ManagementPackClass and then provide a default ObjectQueryOptions.

The last thing of interest is how I make the object more useful.  First by using each one of the Values property on EnterpriseManagementObject and creating a note property, it lets me see the “real” properties of the object (the ones on the Service Manager class).  By adding the name of the class to the TypeNames collection of the psobject, I can then use that with a formatting .ps1xml file so I can customize the output by the Service Manager class.

PS> get-smobject.ps1|ft DisplayName,LastModified -au

DisplayName                   LastModified
-----------                   ------------       8/14/2009 10:48:24 PM       8/14/2009 10:48:24 PM 8/13/2009 8:09:02 PM       8/14/2009 10:48:24 PM       8/14/2009 10:48:24 PM       8/14/2009 10:48:24 PM

Posted August 17, 2009 by jtruher3 in ServiceManager

Creating Data in Service Manager   Leave a comment

In my last post, we saw how we were able to retrieve data from Service Manager, where we also said farewell to scripting.  In this post, I’ll quickly go through how to create instance data in Service Manager.  It was a short farewell to scripting, because unlike the last post were we needed some C# to do what we wanted, we can create most objects in the Service Manager CMDB directly from script.  In order to create instances in Service Manager, we need to use CreatableEnterpriseManagementObject.  The constructor for this object takes a reference to the EnterpriseManagementGroup and a ManagementPackClass.  After this, it’s simply a matter of assigning values to various properties of the object.  Here’s a script that creates 5 instances of Microsoft.Windows.Computer and sets a number of the property values.


$NS   = "Microsoft.EnterpriseManagement"
$EMGT = "${NS}.EnterpriseManagementGroup"
$EMG = new-object $EMGT localhost
$CEMOT = "${NS}.Common.CreatableEnterpriseManagementObject"
$ComputerClass = $EMG.EntityTypes.GetClasses()|?{$ -eq "Microsoft.Windows.Computer"}
1..5 | %{
    $NewComputer = new-object $CEMOT $EMG,$ComputerClass
    $PrincipalNameProperty = $NewComputer.GetProperties()|?{$ -eq "PrincipalName"}
    $Name = "Computer${_}"
    $NewComputer.Item($PrincipalNameProperty).Value = $Name

this should add 5 computers to our system, (computer1 to computer5).

We can check this with our previous cmdlets:

PS> get-smclass$|get-scsmobject | ft DisplayName


Woo hoo!  There are my new instances! However, it’s not quite as simple as this.  Some properties are required and we have to be sure that we provide values for those properties.  So, how can we find out what they are?  These properties are designated as key properties.  We can determine what these key properties are, by inspecting the properties of the newly created object. 

PS> $NS   = "Microsoft.EnterpriseManagement"
PS> $EMGT = "${NS}.EnterpriseManagementGroup"
PS> $EMG = new-object $EMGT localhost
PS> $CEMOT = "${NS}.Common.CreatableEnterpriseManagementObject"
PS> $ComputerClass = $EMG.EntityTypes.GetClasses()|?{$ -eq "Microsoft.Windows.Computer"}
PS> $NewComputer = new-object $CEMOT $EMG,$ComputerClass

PS> $newcomputer.getproperties()|ft key,name,type -au

  Key Name                                Type
  --- ----                                ----
 True PrincipalName                     string
False DNSName                           string
False NetbiosComputerName               string
False NetbiosDomainName                 string
False IPAddress                         string
False NetworkName                       string
False ActiveDirectoryObjectSid          string
False IsVirtualMachine                    bool
False DomainDnsName                     string
False OrganizationalUnit                string
False ForestDnsName                     string
False ActiveDirectorySite               string
False LogicalProcessors                    int
False OffsetInMinuteFromGreenwichTime      int
False LastInventoryDate               datetime
False Owner                             string
False Customer                          string
False Engineer                          string
False Description                       string
False URL                               string
False ServerType                        string
False ObjectStatus                        enum
False AssetStatus                         enum
False Notes                           richtext
False DisplayName                       string

So, I can see that the only the PrincipalName is required to create an instance, and the type of value that I must supply is a string.

In my next post, I’ll look more closely at how to provide values for things other than strings.

Posted August 14, 2009 by jtruher3 in ServiceManager