One of our MVPs brought up an interesting scenario this morning. He tried to create a PowerShell script using SMLets to add a new manual activity to an existing parallel activity. This was his script:
Essentially, his script gets the parallel activity (PAObject), creates a new manual activity (NewMA) using New-SCSMObject, and then tries to create a WorkItemContainsActivity relationship between the PA and the MA using New-SCSMRelationshipObject. When he does this he gets the following error in the script when the New-SCSMRelationshipObject cmdlet is called.
New-SCSMRelationshipObject : A discovery data item was rejected because the item is already bound to another Membership relationship.
At C:\…\test.ps1:21 char:37
+ $NewRel = New-SCSMRelationshipObject <<<< -Relationship $WIcontainsActivityRelationship -Source $PAObject -Target $NewMA -Bulk -ComputerName $SMSRV
+ CategoryInfo : NotSpecified: (:) [New-SCSMRelationshipObject], DiscoveryDataLifetimeDependencyException
+ FullyQualifiedErrorId : Microsoft.EnterpriseManagement.Common.DiscoveryDataLifetimeDependencyException,SMLets.Ne wSCSMRelationshipObject
Why is this happening?
This script would actually work just fine if the relationship type of the relationship that is being created were a reference or containment relationship type. However, in this case System.WorkItemContainsActivity is a relationship type that derives from System.Membership. Membership (and hosting) relationships can only be created at the same time that the related object is being created. In this example, the MA is created first using New-SCSMObject. Then, the script tries to create a membership relationship between the existing PA and existing MA. In order to create this relationship, the (1)MA and the (2)relationship between the new MA and the existing PA must be created at the same time. The way to do this is to create the object and relationship via a type projection. In this example, the PA will be the seed of the type projection and the MA will be created as a child component object of the projection. You can use the New-SCSMObjectProjection cmdlet to create this kind of projection object.
New-SCSMObjectProjection takes basically two important parameters:
1) –Type: The name of the type projection to use. Must be provided as a string (don’t try to pass a type projection object itself)
2) –Projection: A hashtable representing the data to populate the projection with.
The name of the type projection is pretty straightforward. In this case, we don't ship a type projection out of the box that has a Parallel Activity as the seed class and the relationship type System.WorkItemContainsActivity as a component. So, I created a simple MP (link to the file at the end of the blog post) that defines a type projection for this purpose. This is the definition of the type projection:
After importing this MP I can use the new type projection in my script:
Hopefully the first 8 lines look familiar to you already. This $Projection thing on line 9 is wild though! Basically what we have here is some nested hashtables with a special format that is expected.
There are basically two options here:
1) Create a new related object (target object) and relationship to an existing object (“seed” source object)
2) Create a new seed source object and related target objects
The example above is an example of #1. I’ll provide an example of how to do #2 a little later in this post.
To do #1 we need to create a hashtable that has three items in it:
1) The __CLASS item which is equal to the internal name of the class of the seed object. Note: that is two underscores in front of CLASS! Same for __SEED and __OBJECT that you will see below.
2) The __SEED item which is equal to an EnterpriseManagementObject that we get from Get-SCSMObject. There can only be one object here. It cannot be a collection of objects.
3) This last item is a little tricky. The name of the item needs to be the Alias of the component in the type projection. Look at the type projection above and you will see that the alias of the relationship component is ‘ChildWorkItem’. That’s what we need to put in here for the item name. The item is then equal to another hashtable with the following items:
1) The __CLASS is the internal name of the related class that you are going to create an object of. In this case, it is the manual activity class.
2) The __OBJECT item is equal to a another nested hashtable. This hashtable is a name/value pair of all the properties on that class that you want to set. Note: In case you haven’t seen this before the {0} is a special indicator to the system to insert the next ID number in the sequence in place of the {0}.
Once we have defined the hashtable according to the specific format, we just need to pass the hashtable to New-SCSMObjectProjection. Run the script… Voila! A new MA (MA2319) is created and a relationship is created to make it a child of PA2265.
Now, let’s take a look at another example of creating a seed object and a related object at the same time. In this example we’ll create an incident and a related action log entry at the same time.
Let’s assume we are going to work with this type projection:
Note: I used Get-SCSMTypeProjection to find this.
Notice how the seed class of this projection is System.WorkItem.Incident and there is a component that points to System.WorkItem.TroubleTicket.UserCommentLog. The alias of that component is ‘UserComments’. If we want to see what the properties of the System.WorkItem.TroubleTicket.UserCommentLog is we can do something like this:
You can also do the same for the System.WorkItem.Incident class so you know what properties are key, required, and optional.
OK – now let’s write a script!
Notice here that I have replaced the __CLASS with the name of the seed class of this type projection – System.WorkItem.Incident. IMPORTANT!: Instead of using __SEED in this case, I have used __OBJECT. The difference is that __SEED is used to indicate an existing object as the seed object of the projection. __OBJECT is used to create a new object as the seed of the projection. Then, I used the alias of the user comment component of the projection – UserComments. The rest is essentially the same as what we did before but using the System.WorkItem.TroubleTicket.UserCommentLog class instead of the System.WorkItem.Activity.ManualActivity class.
Here is the resulting incident including the action log entry:
Nice!
I’ve packaged up the MP .xml file with the new type projection definition in it and these two sample scripts and made them available on the TechNet Gallery.
http://gallery.technet.microsoft.com/SMLets-Examples-of-New-77c2f411