One of the things that people often ask about is how to use the Service Manager SDK to:
create new objects,
One of the keys to using the SDK in this way is to use type projections.
We have had a few blog posts on this in the past in introduce the concepts and examples:
Getting Started with Type Projections
More with Type Projections
Getting and Working with Type Projections – Basic
These blogs posts were a little abstract though.
This blog post shows you how to work with type projections using incident management as an example.
The Visual Studio project is attached for reference.
static void Main(string args)
//First get a connection to the Management Group
EnterpriseManagementGroup emg = new EnterpriseManagementGroup("localhost");
//Example #1 - Creating a single incident object
Console.WriteLine("Creating an incident object....");
//Get the System.WorkItem.Incident class
ManagementPackClass classIncident =
//Also get the Medium urgency and impact enums
//since they are required values to create a new incident
//More information on working with enums here:
ManagementPackEnumeration enumUrgencyMedium =
ManagementPackEnumeration enumImpactMedium =
//Now create a CreatableEnterpriseManagementObject so we can create a
//new incident object and populate its properties and Commit() it.
CreatableEnterpriseManagementObject cemoIncident =
//Just doing this for demo purposes. Obviously a GUID is not a good display name!
String strTestID = Guid.NewGuid().ToString();
//Set some property values
cemoIncident[classIncident, "DisplayName"].Value = strTestID;
cemoIncident[classIncident, "Title"].Value = strTestID;
cemoIncident[classIncident, "Urgency"].Value = enumUrgencyMedium;
cemoIncident[classIncident, "Impact"].Value = enumImpactMedium;
Console.WriteLine("Incident object created named: " + strTestID);
//Example #2 - Creating a Relationship between to Objects - Incidnet and User via the Affected User relationship
//Get the incident
Console.WriteLine("Creating an relationship between the incidena and a user....");
String strIncidentByTitleCriteria =
String.Format(@"<Criteria xmlns=""http://Microsoft.EnterpriseManagement.Core.Criteria/"">" +
"<Value>" + strTestID + "</Value>" +
ManagementPack mpIncidentLibrary =
//Get the incident using the criteria from above...
EnterpriseManagementObjectCriteria emocIncidnetByTitle =
IObjectReader<EnterpriseManagementObject> readerEmoIncidentAffectedUsers =
EnterpriseManagementObject emoIncident = readerEmoIncidentAffectedUsers.ElementAt(0);
//Get a user..
ManagementPackClass classUser =
IObjectReader<EnterpriseManagementObject> readerEmoDomainUsers =
//Just getting whatever the first user is that comes back for demo purposes
EnterpriseManagementObject emoDomainUser = readerEmoDomainUsers.ElementAt(0);
//Create a Relationship between the service and the user
//System.WorkItemAfectedUser relationship type
ManagementPackRelationship relIncidentAffectedUser =
CreatableEnterpriseManagementRelationshipObject cemroIncidentAffectedUser =
new CreatableEnterpriseManagementRelationshipObject(emg, relIncidentAffectedUser);
//Set the source and target...
//Example #3 - Creating relationships in bulk using Incremental Discovery Data
Console.WriteLine("Creating relationships to affected Windows computers...");
//First get the class and relationship type we want to work with
ManagementPackClass classWindowsComputer =
//System.WorkItemAboutConfigItem relationship type
ManagementPackRelationship relAffectedConfigurationItem =
//Now create a "bucket" (IncrementalDiscoveryData class) for putting
//updates into so we can submit them all at once.
IncrementalDiscoveryData iddRelationshipsToAdd = new IncrementalDiscoveryData();
//Get all the Windows computers in the system.
//This is not typical. Just doing this for demo purposes only.
IObjectReader<EnterpriseManagementObject> readerEmoWindowsComputers =
foreach (EnterpriseManagementObject emoWindowsComputer in readerEmoWindowsComputers)
CreatableEnterpriseManagementRelationshipObject cemroAffectedConfigurationItem =
new CreatableEnterpriseManagementRelationshipObject(emg, relAffectedConfigurationItem);
//Set the source and target...
//Add it to the bucket...
//Example #4 - Getting type projection objects and iterating through them
Console.WriteLine("Getting incidents and showing the users computers that are affected by them...");
//Getting incidents and then list the computers and users they are affecting
ManagementPackTypeProjection mptpIncident =
ObjectProjectionCriteria opcIncident = new ObjectProjectionCriteria(mptpIncident);
IObjectProjectionReader<EnterpriseManagementObject> oprIncidents =
foreach (EnterpriseManagementObjectProjection emopIncident in oprIncidents)
if (emopIncident[relIncidentAffectedUser.Target].Count > 0)
//Show the affected user
foreach (IComposableProjection icpAffectedConfigurationItem in emopIncident[relAffectedConfigurationItem.Target])
//Show each of the affected configuration items
Console.WriteLine("\t" + icpAffectedConfigurationItem.Object.DisplayName);
Console.WriteLine("Done showing incidents with related users and computers.");
//Example #5 - Creating objects and relationships at the same time via type projection
Console.WriteLine("Creating an incident and its relationships via a type projection...");
//First create the seed object
EnterpriseManagementObjectProjection emopIncidentToCreate = new EnterpriseManagementObjectProjection(emg, classIncident);
//Just using this for testing. Obviously using a GUID for a incidnet display name is not a good idea...
Visual Studio Project String strIncidentName = Guid.NewGuid().ToString();
//Set some properties on the object
emopIncidentToCreate.Object[classIncident, "DisplayName"].Value = strIncidentName;
emopIncidentToCreate.Object[classIncident, "Title"].Value = strIncidentName;
emopIncidentToCreate.Object[classIncident, "Impact"].Value = enumImpactMedium;
emopIncidentToCreate.Object[classIncident, "Urgency"].Value = enumUrgencyMedium;
//Then relate it to other objects as needed
IObjectReader<EnterpriseManagementObject> readerUsers =
foreach (EnterpriseManagementObject emoUser in readerUsers )
Console.WriteLine("Incident and relationships created...");
//Example #6 - Updating objects and relationships at the same time via type projection
Console.WriteLine("Updating an incident and its relationships at the same time via a type projection...");
//First get the EnterpriseManagmentObjectProjection
IObjectProjectionReader<EnterpriseManagementObject> oprIncidentsToUpdate =
foreach (EnterpriseManagementObjectProjection emopIncident in oprIncidentsToUpdate)
//Update a property
emopIncident.Object[classIncident, "DisplayName"].Value =
emopIncident.Object[classIncident, "DisplayName"].Value + " - Updated";
//Remove a relationship
foreach (IComposableProjection icpAffectedUser in emopIncident[relIncidentAffectedUser.Target])
//Add a relationship
//Just getting the first user here as an example
EnterpriseManagementObject emoUserToAdd =
Visual Studio Project
I'm wondering when and why you'd want to use emop.Overwrite() rather than emop.Commit(). In one of your many blog posts, I remember seeing a comment for when to use one over the other, but I can no longer find that.
In my case, I'm adding users to the Approvers list of a Review Activity.
.Commit() is typically used when you are creating new things and .Overwrite() should be used when you want to overwrite something (i.e. update it). .Commit() will fail if there is already an object created with the same key property values.
Hi Travis, is it possible to have an example of how to edit an existing incident property by ID?
I couldn't find out how to reference Incident ID but I have since found [Type='WorkItem!System.WorkItem']/Id$ which works. Are these published anywhere?
Travis, thanks very much for this article, it has allowed me to begin a working solution.
These "generic" properties are "documented" here in this blog post at the beginning:
You can put a $ in front of any of those properties and get to that information like you did for $Id
Tim asked you about Commit() and Overwrite(). I find I generally commit for new or existing items and it works ok. I've also tried Overwrite, and it works ok, too.
The problem I have is when a workitem is open for editing in a form.
I have custom tasks that make changes and save the workitem. These work ok, but if I then try and save the workitem by clicking OK I either get an error (about the item being changed by another process) or the changes I made manually on the form have been lost when I re-edit the workitem.
I've tried both Commit() and Overwrite() without much luck. Also, it does not appear possible to refresh a form from a custom task?
I notice that some of your built-in tasks manage all this ok...
What am I doing wrong?
The reason mine work in that scenario and yours dont is because I am using some secret squirrel undocumented APIs that update the in memory instance of the object instead of updating the database directly. The changes that the user makes in this way are committed with any other changes that are made on the form all at the same time and hence there is no error.
These APIs are not publicly communicated because they are changing namespaces in the next release and any code written against them will break. The code that uses them will need to be updated and recompiled to work with the next version of SCSM. If it is absolutely critical for you to use these APIs you can contact me offline to discuss.
@Travis - thanks for the honest answer :)
It isn't critical, no, but it would be nice if R2 has a supported way to do the same thing. For now, I don't allow my custom tasks to be run against workitems that are open in a form, displaying a message intructing the analyst to re-run the task from a view.
I was just wondering how to you set the AffectedUser value? to the current user that is raising the ticket?
It is similar to this call:
except you would get and use a different relationship type instead of relAffectedConfigurationItem.
I'm completely lost - I need to retrieve the logged on user but I am puzzled on how to find the guid for the user class...Is this the ManagementPackId?
You can look up class GUIDs on the ManagedType table in the ServiceManager database. See this blog post for more details on the database schema:
You can also just use the GUID from above in my example. That is the same for all installations of SCSM.
I find there are many Guids in your code. Could you tell me why do you choose those Guid value? For example, in Example 1, you choose Guid "A604B942-4C7B-2FB2-28DC-61DC6F465C68" when you get the System.WorkItem.Incident class. Are all incident class Guid A604B942-4C7B-2FB2-28DC-61DC6F465C68, no matter in which MP, or different in different MP. If former, how to get Guid of system class such as incident class, change request class and so on. If later, how to know the Guid when I write code.
In example 1, you constructed a CreatableEnterpriseManagementObject instance when you created the Incident Class instance. If I construct an EnterpriseManagementObject instance instead, are there any differences?
The GUID of MP elements like classes, views, properties, relationship types, etc. are a hash of the following:
* Management Pack ID
* Management Pack Public Key Token
* Management Pack Element ID
Therefore, in every installation of SCSM (except for internal test builds) the GUIDs for these things are the same.
You can look up these GUIDs in different tables in the database. For example the ManagedType table contains the class GUIDs.
I'm wondering how can I create an incident with its affected user ( having his display name as a String) through sdk