Another forum thread documentation post.
Why are the expansion strings were not replaced in notification templates? In the context of the post, it became clear that the poster had copied the strings from one notification template stored in one of the default MPs into a new notification template stored in a custom MP. Why wouldn’t this work? it’s just computer code things that the system will interpret, why should it care where it is?
Well, let’s start with a breakdown of those strings. they’re actually OMSDK variables that are replaced at run-time with data from the system. to break it down (spaces replaced by BR for readability) :
$Context/Path[Relationship='WorkItem!System.WorkItemAffectedUser' SeedRole='Source' TypeConstraint='System!System.Domain.User']/Property[Type='System!System.Domain.User']/FirstName$
- $ starts and ends a variable. It’s primarily a delimiter for the variable engine but is also used to surrounding meta-properties (i.e. the internal ID can be directly referenced as $ID$) and possibly some other use cases.
- Context is one of the keywords that control the behavior of the variable. Service Manager is based on the OMSDK, which means the Ops Manager variables (Other Reference) (Yet Again) are the basis for these. Context is new for service manager, and is largely undocumented, but in most situations can be read as the root element of the projection that is the data context of the reference.
For a form, the forms data context is a projection, referred to as the form’s projection target.
For a notification template, it’s the projection that is the target of the notification template.
- Path means we are going down the projections path. This allows us to look at related objects in the projection, rather the just the root element.
- Relationship modifies path by specifying which relationship to follow in the brackets with the Relationship element. This needs to be an MP Reference. more on that later.
- SeedRole modifies path by setting which side of the relationship the starting objects is on, in this case, the “context” is the source of the relationship, rather then the target.
- TypeConstraint filters path based on what’s on the other side of the relationship. Yet another MP Reference; this will be important later. In this case, it must be a user.
- Property means we’re reading data from a property of this user, as opposed to pathing down another relationship.
- Type modifies property by controlling which class definition to get the property set from. Each side of a relationship is defined as a specific class, but any class that inherits from that can also be related. i.e. the most common user class is Microsoft.AD.User, which inherits through a lineage of classes.
- The last entry is the property name to get data from, i.e. the FirstName property. this needs to be the internal name of the property, not the display string. The internal name is always in American English, because Microsoft and most of it’s programmers are in Redmond, WA. internal names will also have no spaces or special characters, because those might break the surrounding code. Imagine if the internal name of a property contained >, ], or “, characters typically used to end references.
So why do I keep babbling on about MP References? Well MP references consist of two parts, separated with an Exclamation mark (!). The bit to the right is the name of the element and is required. the bit to the left is the Management Pack Alias, and is omitted, along with the bang for elements in the local MP.
The particularly swift (or well informed) reader will already notice that the MP Alias definition isn’t in the code of the notification template. it’s local to the MP, not a global object, and it’s stored at the top of the management pack. It should be clear why copying a notification template using the UI will fail if you store the new one in a different MP; ‘Workitem!System.WorkItemAffectedUser’ is only valid if the MP alias ‘Workitem’ already exists in the new MP, and points to the MP that contains the element ‘System.WorkItemAffectedUser’ that defines a relationship.
But wait, why does reinserting the sometimes fix the issue? well the insert button is looking for existing MP Aliases, and adding new MP aliases behind the scenes if it can’t find an existing one, but the aliases the console throws in are not always the same as the aliases you want. The console created alias will often look like “Alias_150d3d58_e565_44f1_90da_c4f4181416f9” not “workitem”.
So where do those American English human readable alias in names come from? Human American English Programmers.