July 28, 2011

SCSM Customizing Views / XML / View Logic

Here at New Signature we’ve been using System Center Service Manager (SCSM) for months, enabling us to more quickly automate common tasks and increase our adherence to ITIL best practices. We love the product and the way it helps us achieve our goals, but with any relatively new Microsoft release, there are some quirks to overcome.

Currently the stock user interface of SCSM SP1 is fairly limited, and there are many things that you aren’t able to accomplish without cracking open a management pack (MP) and tinkering around with the XML inside.  With the latest version of SCSM 2012 scheduled to be released in 4-5 months, the situation will not improve anytime soon…which is why you should learn how to mod your own views.

In this post, I will focus on customizing views in SCSM – the simple example I will use revolves around changing the view logic.

EXPORTING YOUR MP
To get to the XML that defines your MP (in which your view is stored), you have to first export it.  Whether you are trying to customize a view or attempting to change the UI of the input forms for a class, you’ll want to first figure out which MP is associated with the task you’re trying to accomplish.  For example, if we’re trying to modify an existing view:

 

1.    Right-click the view –> Edit View –> General –> Management pack
If you’re trying to make a custom view from scratch, you’ll already know what management pack you placed the view inside.

2.    Administration –> Management Packs –> Search for your MP –> Export

 

A few things to keep in mind when exporting MPs – you cannot export a sealed MP (many of the MPs that come out of the box are sealed; any MP that you create will default to unsealed).  The sealed MPs usually have many dependencies on them and changing them could cause things to break.  In our case, since we’re dealing with a MP that we created, it is thus unsealed and thus will export happily.

CUSTOMIZING VIEWS
SCSM does not give us much flexibility when it comes to customizing our views.  It determines the logic for you, and does not provide you with many targeted features.  For example, you can’t create a view that contains all incidents assigned to [Bob User] because you can’t name a user for that field.  Bob User himself can make a view with incidents assigned to himself, but that’s only because we can designate the criteria token “[me]” as a user.

 

What I would like to implement, in the above screenshot, is a view that contains all incidents for which (Assigned to [me] OR Owner==[me]) AND (Status == Active OR Status = Updated) AND (Actual end date==Tomorrow (relative))

However, you can see that it will only let me do (Assigned to [me] AND Owner==[me]) which is useless.  Also, the actual end date wants a hard-set date and relativity does not play nice.

First of all: criteria tokens.  There are a couple of these variables hidden in SCSM, such as the one we’ve already mentioned “[me]”.  Other tokens include:

  • [me] – denotes current user
  • [mygroups] – denotes current user’s group
  • [now] – denotes the current utc time.
  • [today] – denotes today’s datetime.
  • [now + 5s], [today -2d], [today + 5m],[now – 2h] – denotes some variations using s(seconds), d (days), m(months), h(hour).

Source: Zoltan (growup) @ technet

So now we can do (Actual End Date==[today + 1d]) which solves some of our problems.
To get SCSM to let me do (Assigned to [me] OR Owner==[me]) we need to modify the MP XML directly.

INSIDE THE XML

 

This is the view we’ll be dealing with.  Ideally, we want the view to be:

(Assigned to me OR Owner==Me) OR (Status==Breached)

This is where modifying the XML comes in handy.  Let’s browse to the XML file and open it up; using Notepad is perfectly acceptable for this task.  For view logic, which we’ll focus on, we want to locate the Criteria tag.

The above example will generate the following Criteria tag:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
[RAW]

          <Criteria>
            <QueryCriteria Adapter="omsdk://Adapters/Criteria" xmlns="http://tempuri.org/Criteria.xsd">
              <Criteria>
                <FreeformCriteria>
                  <Freeform>
                    <Criteria xmlns="http://Microsoft.EnterpriseManagement.Core.Criteria/">
                      <Expression>
                        <And>
                          <Expression>
                            <SimpleExpression>
                              <ValueExpressionLeft>
                                <GenericProperty Path="$Context/Path[Relationship='CustomSystem_WorkItem_Library!System.WorkItemAssignedToUser']$">Id</GenericProperty>
                              </ValueExpressionLeft>
                              <Operator>Equal</Operator>
                              <ValueExpressionRight>
                                <Token>[me]</Token>
                              </ValueExpressionRight>
                            </SimpleExpression>
                          </Expression>
                          <Expression>
                            <SimpleExpression>
                              <ValueExpressionLeft>
                                <GenericProperty Path="$Context/Path[Relationship='CustomSystem_WorkItem_Incident_Library!System.WorkItem.IncidentPrimaryOwner']$">Id</GenericProperty>
                              </ValueExpressionLeft>
                              <Operator>Equal</Operator>
                              <ValueExpressionRight>
                                <Token>[me]</Token>
                              </ValueExpressionRight>
                            </SimpleExpression>
                          </Expression>
                          <Expression>
                            <SimpleExpression>
                              <ValueExpressionLeft>
                                <Property>$Context/Property[Type='CustomSystem_WorkItem_Incident_Library!System.WorkItem.Incident']/Status$</Property>
                              </ValueExpressionLeft>
                              <Operator>Equal</Operator>
                              <ValueExpressionRight>
                                <Value>{5e2d3932-ca6d-1515-7310-6f58584df73e}</Value>
                              </ValueExpressionRight>
                            </SimpleExpression>
                          </Expression>
                        </And>
                      </Expression>
                    </Criteria>
                  </Freeform>
                </FreeformCriteria>
              </Criteria>
            </QueryCriteria>
          </Criteria>

 [/RAW]

We want to preserve the initial tag sequence Criteria -> QueryCriteria -> Criteria -> FreeformCriteria -> Freeform -> Criteria.

To begin parsing this block of code, let’s start off with the Expression tag, which is interpreted as parentheses. We want to surround our entire logic statement with parentheses.  As you can see, the <And> tag contains three <Expression> tags inside of it; this means that we’re ANDing three items together (which is not what we want).

Let’s start by changing it to (Assigned to me OR Primary Owner = me).  We can begin by using an <Or> tag around the two Expressions that we want.  Notice the red parts indicate how we can tell which Expression is which.  The first expression tells us it represents the “Assigned to” property, and it’s Token is “[me]”.  The Operator is “Equal”, and hence we have “Assigned to = [me]”.  We could change each of these fields if we saw fit (perhaps we wanted all incidents that weren’t assigned to me).


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[RAW]

                       <Expression>
          <Or>
                          <Expression>
                            <SimpleExpression>
                              <ValueExpressionLeft>
                                <GenericProperty Path="$Context/Path[Relationship='CustomSystem_WorkItem_Library!System.WorkItemAssignedToUser']$">Id</GenericProperty>
                              </ValueExpressionLeft>
                              <Operator>Equal</Operator>
                              <ValueExpressionRight>
                                <Token>[me]</Token>
                              </ValueExpressionRight>
                            </SimpleExpression>
                          </Expression>
                          <Expression>
                            <SimpleExpression>
                              <ValueExpressionLeft>
                                <GenericProperty Path="$Context/Path[Relationship='CustomSystem_WorkItem_Incident_Library!System.WorkItem.IncidentPrimaryOwner']$">Id</GenericProperty>
                              </ValueExpressionLeft>
                              <Operator>Equal</Operator>
                              <ValueExpressionRight>
                                <Token>[me]</Token>
                              </ValueExpressionRight>
                            </SimpleExpression>
                          </Expression>
          </Or>
        </Expression>

 [/RAW]

By surrounding these two expressions with the <Or> tag we now have part of the logic we want: (Assigned to me OR Owner=me).  Note the parentheses around the <Or> tag.  This allows any higher-nested logic tags to consider this as one single statement.  Remember PEMDAS? Order of operations is critical!

You generally want to put Expression tags before your logic tags, such as <Expression> <And> or <Expression> <Or>.  Otherwise, your view may not play nice, so put <Expression>s even when they are not necessary (such as the <Expression> around the entire Boolean statement which is required).

Next, we still want to AND the above expression with our Status=Breached condition.   We already have the code for this:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[RAW]

                            <Expression>
                            <SimpleExpression>
                              <ValueExpressionLeft>
                                <Property>$Context/Property[Type='CustomSystem_WorkItem_Incident_Library!System.WorkItem.Incident']/Status$</Property>
                              </ValueExpressionLeft>
                              <Operator>Equal</Operator>
                              <ValueExpressionRight>
                                <Value>{5e2d3932-ca6d-1515-7310-6f58584df73e}</Value>
                              </ValueExpressionRight>
                            </SimpleExpression>
                          </Expression>

       
 [/RAW]

Notice that the “Breached” status is referenced by a GUID; so are the rest of the Incident Statuses (Active, Resolved, In Progress, and any custom ones you may have added).

Important: Once you re-import this modified XML into SCSM, you won’t be able to modify it again using the GUI. If you want to modify your view after you have re-imported it, you will have to go into the XML.  If you wanted to change our view to Status=Active, then you would have to obtain the GUID for the “Active” status first and then replace the GUID value highlighted in green.  This can be done via powershell (see end of post) or by making another temporary view that uses “Status=Active”, and then browsing into that view’s XML.

We can now combine our two expressions into one whole:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
[RAW]

     <Criteria>
            <QueryCriteria Adapter="omsdk://Adapters/Criteria" xmlns="http://tempuri.org/Criteria.xsd">
              <Criteria>
                <FreeformCriteria>
                  <Freeform>
                   <Criteria xmlns="http://Microsoft.EnterpriseManagement.Core.Criteria/">
                     <Expression>
                       <And>
          <Expression>
           <Or>
                          <Expression>
                            <SimpleExpression>
                              <ValueExpressionLeft>
                                <GenericProperty Path="$Context/Path[Relationship='CustomSystem_WorkItem_Library!System.WorkItemAssignedToUser']$">Id</GenericProperty>
                              </ValueExpressionLeft>
                              <Operator>Equal</Operator>
                              <ValueExpressionRight>
                                <Token>[me]</Token>
                              </ValueExpressionRight>
                            </SimpleExpression>
                          </Expression>
                          <Expression>
                            <SimpleExpression>
                              <ValueExpressionLeft>
                                <GenericProperty Path="$Context/Path[Relationship='CustomSystem_WorkItem_Incident_Library!System.WorkItem.IncidentPrimaryOwner']$">Id</GenericProperty>
                              </ValueExpressionLeft>
                              <Operator>Equal</Operator>
                              <ValueExpressionRight>
                                <Token>[me]</Token>
                              </ValueExpressionRight>
                            </SimpleExpression>
                          </Expression>
           </Or>
          </Expression>
                          <Expression>
                            <SimpleExpression>
                              <ValueExpressionLeft>
                                <Property>$Context/Property[Type='CustomSystem_WorkItem_Incident_Library!System.WorkItem.Incident']/Status$</Property>
                              </ValueExpressionLeft>
                              <Operator>Equal</Operator>
                              <ValueExpressionRight>
                                <Value>{5e2d3932-ca6d-1515-7310-6f58584df73e}</Value>
                              </ValueExpressionRight>
                            </SimpleExpression>
                          </Expression>
                        </And>
                      </Expression>
                    </Criteria>
                  </Freeform>
                </FreeformCriteria>
              </Criteria>
            </QueryCriteria>
          </Criteria>


 [/RAW]

IMPORTING MPS
Last but not least, we need to import this back into the console.

Administration –> Select your MP –> Import

If it throws an error, make sure you:

  1. Closed your tags properly
  2. Referenced existing tokens and operators
  3. Indented tags properly (nested tags should be further indented)

 

SCSM will play nice with your whitespace, but it’s better not to take chances.

More information can be found at MSFT’s SCSM blog or Travis Wright’s posts, such as “Hacking Management Pack XML Like a Pro“.

Administration -> Select your MP -> ImportAdministration -> Select your MP -> Import

Comments are closed.