THURSDAY, FEBRUARY 23, 2012

Change Management Workflow Approval Scripts in Service-now.com

S

ervice-now.com provides a really cool Graphical Workflow engine to help manage workflows for different tasks. This graphical workflow engine is particularly useful when working with approvals for Change Requests. As a Service-now.com consultant I’ve found that change approvals usually fall into just a few different types but new administrators and consultants sometimes don’t know the best way to implement approvals. In this post I’ll share some of the common change workflow approval methods and scripts I’ve seen used before. I wouldn’t be surprised to see this list grow over time and I know I haven’t seen all of the common methods. If you have something you’ve used before please comment on this post or use the ‘Contact’ link above to send in your suggestion to share.

Simple Approvers Selection (Select Specific Group)

The simplest (and most common) type of approval is to select specific groups or users to approve the change. The screenshot below shows how you can use the standard reference field lookup to select a group to add as approvers to the change request. This method is commonly used when you want to have a specific group (like the CAB) approve at some point in your workflow.

Simple Approvers Selection (Drill to Related Records)

Another common method is to drill into the change request itself and pull the approvers from a field on the change. This method is commonly used when you want to have something like a manager approval for the person requesting the change (as shown below) or maybe when you want to have the assignment group on the change request approve.

Advanced Approvers Script (Approval Groups for all Change CIs)

The Service-now.com Graphical Workflow mechanism also allows you be even more complex in the selection of approvals for your change requests. You can use script with GlideRecord queries to return any users or groups you want to have approve. The one thing to keep in mind with these scripts is that you need to return group records if your workflow activity is a Group Approval type and user records if your workflow activity is a User Approval type.
One common request I’ve seen before that requires a script is to add approval groups based on the Configuration Items associated to the change request. Chances are you’ll have multiple CIs associated on the ‘Affected CIs’ related list for the change. This script queries for those records and then adds the groups from the ‘Approval Group’ field on each CI.

//Initialize an answer array to be returned
var answer = [];

//Add the primary CI approval group to the array
answer.push(current.cmdb_ci.change_control);

//Add the Affected CIs list approval groups to the array
var affCIs = new GlideRecord('task_ci');
affCIs.addQuery('task', current.sys_id);
affCIs.query();
while(affCIs.next()){
  answer.push(affCIs.ci_item.change_control);
}

Advanced Approvers Script (Approval Groups for all Impacted Change CIs)

There are some rare cases where clients want to pull approval groups from other CIs that will be impacted by the change based on CI relationships. For these cases you can use the CIUtils2 script I created to walk the CI relationship tree and find the impacted CIs that you need to add approvals for. In order to use these scripts you’ll need to add the CIUtils2 script include to your system first. You’ll also want to use this type of approval method sparingly since it involves a sometimes resource-intensive traversal of your CMDB (if you have hundreds of thousands of CIs). It’s also pretty expensive process-wise as well. Do you really want to require approval from every single group in your company when your network team needs to make a change to the core router? Maybe so, maybe not, but either way you’re probably talking about a lot of approvals because that CI impacts so many other CIs in your environment.

Impacted CIs approval scripts
–This first example returns Approval Groups for all of the Business Services impacted by the change request–

//Initialize a variable for the CIUtils2 Script include
var ciu = new CIUtils2();
//Initialize an answer array to be returned
var answer = [];

//Add any impacted business services for the change
var allCIs = ciu.cisAffectedByTask(current);

//Query for all CIs and return Approval Groups
for (var i = 0; i < allCIs.length; i++) {
   var cis = new GlideRecord('cmdb_ci');
   cis.addQuery('sys_id', allCIs[i]);
   cis.query();
   if (cis.next()) {
      answer.push(cis.change_control);
   }
}

–This example returns Approval Groups for all of the Business Services impacted by the change request AND Approval Groups for all directly Affected CIs on the change request. It utilizes the ‘CheckDuplicates‘ function I wrote to eliminate some unnecessary processing.–

//Initialize a variable for the CIUtils2 Script include
var ciu = new CIUtils2();
//Initialize an answer array to be returned
var answer = [];
//Initialize an array to gather and store all impacted CIs
var allCIs = [];

//Add the primary CI to the CI array
allCIs.push(current.cmdb_ci);

//Add the Affected CIs list to the CI array
var affCIs = new GlideRecord('task_ci');
affCIs.addQuery('task',current.sys_id);
affCIs.query();
while (affCIs.next()) {
   allCIs.push(affCIs.ci_item);
}

//For each directly affected CI on the change, add any impacted business services
for (var i = 0; i < allCIs.length; i++) {
   allCIs = allCIs.concat(ciu.cisAffectedByCI(allCIs[i]));
}

//Remove duplicate CIs from the array
allCIs = checkDuplicates(allCIs);

//Query for all CIs and return Approval Groups
for (var j = 0; j < allCIs.length; j++) {
   var cis = new GlideRecord('cmdb_ci');
   cis.addQuery('sys_id', allCIs[j]);
   cis.query();
   while (cis.next()) {
      answer.push(cis.change_control);
   }
}

function checkDuplicates(a) {
   //Check all values in the incoming array and eliminate any duplicates
   var r = []; //Create a new array to be returned with unique values
   //Iterate through all values in the array passed to this function
   o:for(var i = 0, n = a.length; i < n; i++){
      //Iterate through any values in the array to be returned
      for(var x = 0, y = r.length; x < y; x++){
         //Compare the current value in the return array with the current value in the incoming array
         if(r[x]==a[i]){
            //If they match, then the incoming array value is a duplicate and should be skipped
            continue o;
       }
      }
      //If the value hasn't already been added to the return array (not a duplicate) then add it
      r[r.length] = a[i];
     }
   //Return the reconstructed array of unique values
   return r;
}

Comments

Posted On
Dec 14, 2010
Posted By
Travis Henning

This is great script and will work great in our organization. One thing I’m looking to do is build it into a UI Action rather than the workflow so the user can click a button when they’ve added the affected CIs. Is there anything different that needs to be done to push the approver groups from the array to the related list of group approves in the change record?

Posted On
Dec 14, 2010
Posted By
Mark Stanger

The scripts above are designed specifically for use in graphical workflow approval activities. Using them in a UI action would require the addition of some code to process the answer array and then create the approval records using a GlideRecord insert. You’re probably better off using your UI action to advance the workflow by setting some value in the change record. Then your workflow woulld have control over the approval process.

Posted On
Dec 14, 2010
Posted By
Travis Henning

So if we added the approvers via GlideRecord insert, the Manual Approval Coordinator of the workflow that is already running against the change record won’t capture and manage the approvals?

Posted On
Dec 14, 2010
Posted By
Mark Stanger

It should. I guess the point I was trying to make is that automated anything (in a workflow for example) is usually better than the manual alternative.

Posted On
Feb 28, 2011
Posted By
Ed Perkins

Mark,

When I tried putting this into a Fall 2010 level instance. The checkDuplicates function gives me an error on the continue o; statement. Any thoughs?

Thanks.

Ed

Problem at line 66 character 24: Missing ‘;’

continue o;

Problem at line 66 character 25: Identifier ‘o’ already declared as live*

continue o;

Problem at line 66 character 25: Expected an assignment or function call and instead saw an expression.

continue o;

Posted On
Feb 28, 2011
Posted By
Mark Stanger

You’ll get the same thing on the Spring 2011 build that’s on demo right now but you can ignore those errors. The script is still fine, but the syntax checker is being a little bit more stringent than it needs to be. It thinks that’s not valid syntax in the script, but the script will save and execute just fine.

Posted On
Nov 08, 2011
Posted By
narinder

is there a way we can select specific group members for a group for approval. I dont want everyone in a group getting a approval request

Posted On
Nov 08, 2011
Posted By
Mark Stanger

You can, but you would have to have some indicator on those records so that you could identify them with a script. If you were to do something like that you would need to use a ‘User approval’ activity instead of a ‘Group approval’ activity though.

Posted On
Nov 08, 2011
Posted By
narinder

Ahhhh ok, soo if i do this in a user approval activity….. my script looks like this below

answer = [];
var stream_sys_id = current.u_deal_business_stream;
var list = current.u_selected_stream_approvers.toString();
var gr = new GlideRecord(‘u_deal_business_stream’);
gr.addQuery(‘sys_id’,'=’,stream_sys_id);
gr.query();
if(gr.next())
{
var group = gr.u_business_stream;
answer.push(group); < —–Group ID
}

var grm2 = new GlideRecord(‘sys_user_grmember’);
grm2.addQuery(‘group’,'=’, group);
grm2.addQuery(‘user’,'=’ ’23rd2e3e23e23e23e23ee32fwewe3′)
grm2.query();
if(grm2.next())
{
answer.push(grm2.user); <——-User ID
}

But thing is, it does’nt create the group approval….. just create the user approval……

Posted On
Nov 08, 2011
Posted By
Mark Stanger

That’s right. If you aren’t pulling all of the members of the group in, it should be treated as a user approval rather than a group approval. There’s no way I know of to do what you want with a group approval activity within a workflow. I suppose you could set up a business rule on the ‘sysapproval_approver’ table to abort the insertion of approval records for users who should not approve, but I’m not sure how that will scale across different workflows.

Posted On
Nov 08, 2011
Posted By
narinder

Thanks for the feedback. Got to think about plan B now

Leave a Reply


Notify me of followup comments via e-mail. You can also subscribe without commenting.

Latest Comments

  • Mark Stanger: It looks like it should work. Have you tried it out yet?
  • John Gilaspy: I’ve been using the Export Workflow function for awhile, and was wondering the following would...
  • Wayne: Thank you very much Mark
  • Mark Stanger: These scripts run server-side and are placed in the script field of a workflow ‘Wait for...