Workflow that Triggers on Relationship Add or Remove

It’s easy to create workflows that trigger on property changes such as when the status of an Incident changes from Active to Resolved.  However, you can’t use the console or Authoring tool to configure workflows that have criteria for relationship changes.

Fortunately with a bit of XML tweaking it is possible to trigger a workflow when a relationship is created or when it is deleted.

This method will work with email subscriptions, console workflows or authored workflows created using the Authoring tool.

In this example I’ve used the Authoring tool to create a workflow that generates an event in the Operations Manager Event Log when the Affected User is set on an Incident.

Regardless of your method it is important to ensure you set some kind of criteria (doesn’t really matter what you choose) as that makes the XML easier to edit.  I’ve used a criteria based on the Affected User Company property.

I’ve then configured the rest of the workflow the way I want it and saved my configuration.

Next I edit the unsealed management pack.  To do this for an email subscription or a console workflow, export the management pack first.

The rest of the configuration will be done by editing the management pack using an XML editor.  The section I want is the subscription which is located in the Rule under the Rules section.

<Subscription>
  <WindowsWorkflowConfiguration>
    <AssemblyName>DevTestIncidentWorkflows</AssemblyName>
    <WorkflowTypeName>WorkflowAuthoring.DevTestIncidentWorkflows</WorkflowTypeName>
    <WorkflowParameters></WorkflowParameters>
    <RetryExceptions></RetryExceptions>
    <RetryDelaySeconds>60</RetryDelaySeconds>
    <MaximumRunningTimeSeconds>300</MaximumRunningTimeSeconds>
  </WindowsWorkflowConfiguration>
</Subscription>

I can see the conditions in the subscription.  I need to replace the subscription with my relationship subscription in order to set the criteria to be when a relationship is created between an Incident and the Affected User.

<RelationshipSubscription RelType="$MPElement[Name='System_WorkItem_Library!System.WorkItemAffectedUser']$" SourceType="$MPElement[Name='System_WorkItem_Library!System.WorkItem']$" TargetType="$MPElement[Name='System!System.User']$">
  <AddRelationship>
  </AddRelationship>
</RelationshipSubscription>

The key difference here is that we are using a RelationshipSubscription.  The relationship is made up of the relationship property, the target and the source.  The properties you need can be found by looking at class properties using the Authoring tool, or by using PowerShell.  For example:

$Class = Get-SCSMClass | where {$_.DisplayName -eq 'Incident'}
$Class.PropertyCollection | format-table DisplayName,Name,Type

Lets break the relationship down.  The first part identifies the relationship.

Name='System_WorkItem_Library!System.WorkItemAffectedUser'

This tells the workflow to use the System.WorkItemAffectedUser relationship that can be found in the System_WorkItem_Library management pack.  System_WorkItem_Library must match the name of the reference at the beginning of this management pack.  E.G:

<Reference Alias="System_WorkItem_Library">
  <ID>System.WorkItem.Library</ID>
  <Version>7.5.3079.0</Version>
  <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
</Reference>

The second part identifies the source class.

Name='System_WorkItem_Library!System.WorkItem'

In this case the source class is System.WorkItem.  Hang on… aren’t we supposed to be using the Incident class?  Well, the Incident class is derived from the abstract class Trouble Ticket, which, in turn is derived from the Abstact class Work Item.  This means the relationship from Work Item is also present in Incident.

More information on Abstract classes can be found here.

The third and final part of the relationhip is the target class.

Name='System!System.User'

Again, although we want to use the Active Directory User class, we really want the base class that the relationship is derived from.  This is the User class.

So my new subscription should look like this:

<DataSources>
  <DataSource ID="DS" TypeID="SystemCenter1!Microsoft.SystemCenter.CmdbInstanceSubscription.DataSourceModule">
    <Subscription>
      <RelationshipSubscription RelType="$MPElement[Name='System_WorkItem_Library!System.WorkItemAffectedUser']$" SourceType="$MPElement[Name='System_WorkItem_Library!System.WorkItem']$" TargetType="$MPElement[Name='System!System.User']$">
         <AddRelationship>
        </AddRelationship>
      </RelationshipSubscription>
      <PollingIntervalInSeconds>60</PollingIntervalInSeconds>
      <BatchSize>100</BatchSize>
    </Subscription>
  </DataSource>
</DataSources>

If I wanted the workflow to trigger when the relationship is deleted between an Incident and the Affected User I would use this type of subscription instead:

<DataSources>
  <DataSource ID="DS" TypeID="SystemCenter1!Microsoft.SystemCenter.CmdbInstanceSubscription.DataSourceModule">
    <Subscription>
      <RelationshipSubscription RelType="$MPElement[Name='System_WorkItem_Library!System.WorkItemAffectedUser']$" SourceType="$MPElement[Name='System_WorkItem_Library!System.WorkItem']$" TargetType="$MPElement[Name='System!System.User']$">
        <DeleteRelationship>
        </DeleteRelationship>
      </RelationshipSubscription>
      <PollingIntervalInSeconds>60</PollingIntervalInSeconds>
      <BatchSize>100</BatchSize>
    </Subscription>
  </DataSource>
</DataSources>
Advertisements

Oh No, The CI Object Picker Only Shows Key Values!

I get this question a lot…

“I’ve created a new class and created a relationship from another class to it.  I’ve configured a form that has a Single Instance Picker that targets my new class.  When I open the form in the SCSM console, instead of seeing the friendly name of my class records, I instead see the values of the key property.”

It’s a common adventure to create a Name property in your new class.  For example, you create a CI class called “VDIPools”, with  a key property of “VDIPoolID”.  The key property auto-increments and has a default value of “VDIP{0}”.  You need a clear way of identifying the pools so you create a string property called “VDIName”.  You then create  a new form for use when creating or editing your VDI Pool records, and include all your customer properties.

You  seal up your management packs, import them into SCSM, and create a CI for a VDI Pool.

posts-vdipoolscrnsht01

You then open a new CR and want to add your VDI Pool as a related CI.  When the object picker form opens, instead of seeing your VDI Pool Names, you see the values of your “VDI Pool ID” key class property  (See screenshot).  Which to be frank is neither use to man nor beast.

posts-vdipoolscrnsht02

The object picker form that is dynamically generated by the SCSM console automatically uses the class property “DisplayName”.  If you choose not to populate this property in your class CIs then the key property is shown instead, either in object pickers, or class views, or wherever it is displayed.

There are two solutions to resolve the issue.  One simple and one less so.

Simple Solution

Instead of using “VDI Pool Name”, use the built in CI property that is automatically inherited when you create any CI class of “DisplayName”.

It really is that simple.  This means that you maintain your ‘ID’ key property (which must be unique for each record), and can edit the “DisplayName” property as many times as you like.

Not So Simple Solution

The key can be set on any string value you like, so you could set your “VDIPoolName” property as your key instead of having “VDIPoolID”.  Your form can then use this property instead of the “DisplayName” property.  As the object picker automatically displays the contents of the key when the “DisplayName” property is empty you will see your friendly names.

The downside is that you will never, ever be able to edit your VDI Name, so if you make a spelling mistake or the name of the actual VDI Pool changes later on, you would have to delete the record and recreate it in order to change the VDI Name of your class records.  This is because the contents of a string property that is marked as a key are fixed in stone once the records is first committed.  Deleting a record and recreating it doesn’t sound that hard, but think of all the relationships you have between your record and other items such as Incidents, Service Requests, Users, Computers, etc, etc.  Once you delete the record you also delete all those relationships, and you’ll be hard pressed to recreate them for closed IRs, particularly if they’ve been purged from the Operational DB post import into the DW.