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

PowerShell – Dynamically Adding the Cireson Asset Management Organisation to a Work Item

I wrote a post a little while back that demonstrates how to automatically add the relevant customer to an Incident.  It assumes I created a new class called Customer Organisation.

However, if you are using the Cireson Asset Management app then you could use the Organisation class that comes with this app.

This assumes you author a relationship between the Organisation class and the Incident Class.

I use the same command to store the relationship as a variable.

#Store the relationship types as a variables
$CORel = Get-SCSMRelationship -Name "RelatedCustomerOrganisation"

Here is the key difference in the script – specifying the Cireson AM Organisation.

# Obtain the Customer Organisation where the name matches the users Company property
$CO = Get-SCSMClassInstance -Class (Get-SCSMClass -Name Cireson.AssetManagement.Organization) | ? {$_.DisplayName -eq $AU.Company}

The full script is here.

Import-Module 'C:\Program Files\Microsoft System Center 2012 R2\Service Manager\Powershell\System.Center.Service.Manager.psd1'

#Store the relationship types as a variables
$CORel = Get-SCSMRelationship -Name "RelatedCustomerOrganisation"
$AURel = Get-SCSMRelationship -Name "System.WorkItemAffectedUser"

# Get the Incident
$IR = Get-SCSMClassInstance -Class (Get-SCSMClass -Name System.WorkItem.Incident) | ? {$_.ID -eq "$GUID"}

# Use the method to return the related Affected User object GUID and save it to a variable
$AffectedUserGUID = $IR.GetRelatedObjectsWhereSource($AURel.ID).EnterpriseManagementObject.id.GUID

# If related Affected User is returned then process the remainder of the script
if ($AffectedUserGUID -ne $null)

{

    # Obtain CI info about the Affected User
    $AU = Get-SCSMClassInstance -ID $AffectedUserGUID

    # Obtain the Customer Organisation where the name matches the users Company property
    $CO = Get-SCSMClassInstance -Class (Get-SCSMClass -Name Cireson.AssetManagement.Organization) | ? {$_.DisplayName -eq $AU.Company}

    # If a match between the user and the Customer Organisation is found then create the relationship
    if ($CO -ne $null)

        {

            #Create the relationship between the Incident and the Customer Organisation CI
            New-SCRelationshipInstance -RelationshipClass $COREL -Source $CO -Target $IR

        }

}

SCSM HTML 5 Portal – Customise the Size of a String Property

When a string property is used in a Request Offering it is displayed as a small single line text box in the portal.  It will auto expand as the user types, however it doesn’t accept carriage returns.  If you hit the Enter key from the text box you will submit the Request Offering instead.

To resolve this add the following code snippet to the MakeForm.cshtml located in C:\inetpub\wwwroot\SelfServicePortal\Views\Home.

else if (item["Prompt"].ToString().Equals("Description"))
{
    string regexToolTip = string.Empty;
    if (item.ContainsKey("ToolTip"))
    {
        regexToolTip = item["ToolTip"].ToString();
    }

    <label for="@item["Prompt"].ToString()" data-required="@item["Optional"].ToString()">@item["Prompt"].ToString()</label>
    <textarea cols="40" rows="10" name="@item["PathSend"].ToString()" id="@item["Prompt"].ToString()" @item["Optional"].ToString() value='@Request[item["PathSend"].ToString()]' data-toggle="tooltip"> </textarea>
<div class="error-text">@ErrorResults.Find(m => m.MemberNames.ElementAt(0).Equals(item["PathSend"].ToString()))</div>
}

It must be inserted before the ‘else’ statement that is at the end of the fav_name_email section.  This section is towards the end of the file and looks like this:

<div class="fav_name_email section">
  @foreach (var item in formData)

The key part of the code snippet is in the first line.  In this example I have used “Description”.  It must match the name of the question in the Request Offering.  For example if you have used “Please enter a description” as your question, then the line must be:

else if (item["Prompt"].ToString().Equals("Please enter a description"))

It is also case sensitive.

N.B. it is advisable to backup the files before modifying them.  The Portal Updates patches are designed to read the date stamp on the files and compare it to the last update installation date.  If they match then the file will be overwritten, if they don’t match (I.E. you’ve edited them) then they won’t be updated.  So prior to any update copy the default files back in first.  Yes, there is potential that all your changes will be wiped out by a patch.

The problem here is that you have to add the code snippet for each string value you want to use (assuming you don’t want the default text box) for every question that is worded differently.  It is easier to use a simple common term in your Request Offerings such as “Description”.

This code works with Update 3 for the System Center 2012 R2 Service Manager HTML 5 Portal.

So now that the text box is larger, and accepts carriage returns the font needs to be updated otherwise it will look like type writer text.  To do this add the following code snippet to a file called Custom.CSS and drop it in C:\inetpub\wwwroot\SelfServicePortal\Content\CSS

.section textarea {
 font-family:”Segoe UI”;
width: 24em;
 border:1px solid #BBB;
 }