Subscribe to Multiple CIs at the Same Time in ServiceNow

/, Scripting/Subscribe to Multiple CIs at the Same Time in ServiceNow

Subscribe to Multiple CIs at the Same Time in ServiceNow

Awhile ago I was asked by a client to help them get set up with the ServiceNow Subscription-based Notification plugin. I had previewed the functionality but really hadn’t worked with it very much. As I dug deeper I realized that the standard setup wasn’t going to work for them. Subscription-based notifications are really not intended to be used on a bulk-subscription basis. The idea is that you might pick a handful of CIs that you are interested in and subscribe to them.

The needs that my client had brought to light the following questions:

1How can I easily subscribe to multiple CIs without having to click through the creation of a single subscription record for each CI? If I want to subscribe to the 50 network devices I’m responsible for I don’t want to have to set each of these up one-by-one.

2How can I use CI subscription notifications and not spam the end-user with a notification for each CI? An example of this would be a system administrator who is responsible for a cluster of web servers. A configuration change on one of them typically means a configuration change on all of them. We don’t want to be sending the admin an email for each of the 100 servers every time an update is made to the change ticket.

Shown below is the solution that we came up with…

Just a warning, this is some fairly advanced stuff so don’t jump in at the deep end with this unless you’ve had a chance to dip your toes in the ServiceNow administration waters already!

Question #1:How can I easily subscribe to multiple CIs without having to click through the creation of a single subscription record for each CI?
I accomplished this by creating a UI action link on the user record that redirects to record producer catalog item. The record producer collects the CI and user information, creates the subscriptions, and redirects the user to his/her subscription page.

CI Subscription Form

Multiple CI Subscription Form

1) Create a Record producer with 3 variables.
-configuration_items (list collector that references the ‘cmdb_ci’ table)
-user (reference variable that references the user table –This will be hidden by a catalog client script)
-email (single line text variable –This will be hidden by a catalog client script)

-The record producer should point to the ‘Notification Messages’ table
-The record producer should have the following in the ‘Script’ field.

var pUser = producer.user.toString();
var pEmail = producer.email.toString();
var pCIs = producer.configuration_items.toString();

//Find the user 'Primary email' notification device
var rec = new GlideRecord('cmn_notif_device');
rec.addQuery('user', pUser);
rec.addQuery('type', 'Email');
rec.addQuery('email_address', pEmail);
rec.query();
rec.next();

//Parse the list of configuration items
var list = pCIs;
var array = list.split(',');
for (var i=0; i < array.length; i++) {
//Query to see if this user has already subscribed to this CI
var nm = new GlideRecord('cmn_notif_message');
nm.addQuery('user', pUser);
nm.addQuery('configuration_item', array[i]);
nm.query();
if(!nm.next()){
//Create the CI notification records
var rec1 = new GlideRecord('cmn_notif_message');
rec1.initialize();
rec1.notification.setDisplayValue('CI affected');
rec1.user = pUser;
rec1.device = rec.sys_id;
rec1.configuration_item = array[i];
rec1.insert();
}
}

//Do not submit this record
current.setAbortAction(true);

//Add a notification message and redirect the user to the subscriptions page
gs.include('FormInfoHeader');
var fi = new FormInfoHeader();

producer.redirect = 'notification_preferences.do?sysparm_user=' + producer.user.toString() + '&sysparm_email=' + producer.email.toString();
var s = 'Subscriptions have been created.<br/>';
s += 'You can modify the subscription settings for individual configuration items below. <br/>';

fi.addMessage(s);

-Create an ‘onLoad’ catalog client script for your record producer with the following script. The purpose of this script is to populate the ‘user’ and ’email’ fields with data passed in from the UI action link on the user form.

function onLoad() {
//Hide the user and email fields
g_form.setDisplay('user', false);
g_form.setDisplay('email', false);

//Get parameters from url and populate them into the user and email fields
var url = document.location.toString();
var userKey = 'sysparm_user=';
var emailKey = 'sysparm_email=';
var userPosition = url.indexOf(userKey);
var emailPosition = url.indexOf(emailKey);
if (userPosition != -1){
var user = url.substr(userPosition+userKey.length, 32);
g_form.setValue('user',user);
}
if (emailPosition != -1){
var email = url.substr(emailPosition + emailKey.length);
g_form.setValue('email',email);
}
}

2) Create a ‘Form link’ UI action link on the ‘sys_user’ table that redirects to your new Record producer
-Condition: gs.getUserID() == current.sys_id || user.hasRole(‘admin’)
-Script: Note–You’ll need to put the sys_id of your record producer in here

gs.setRedirect('com.glideapp.servicecatalog_cat_item_view.do?sysparm_id=YOUR_ITEM_SYSID_HERE&sysparm_user=' + current.sys_id + '&sysparm_email=' + current.email);

Question #2:How can I use CI subscription notifications and not spam the end-user?

This can be accomplished by creating a business rule on the table of your choice (mine was on the ‘change_request’ table) with the following parameters. The business rule triggers an event that sends an email notification.

–The first thing you’ll want to do is de-activate the ‘Affected ci notifications’ business rule. This solution works separately from the trigger in that business rule.

1) Create the business rule
Name: Notify subscribers
Table: change_request (or whatever you choose)
-Runs after insert/update
Condition:

current.approval.changesFrom('not requested') || current.approval.changesFrom('rejected')

-Note: I chose this condition so that the notification would only go out when approval on the change was requested. You should modify this according to your needs.
Script:

var subscribers = getSubscribers();
gs.eventQueue('task.notify.subscribers', current, gs.getUserID(), subscribers);

function getSubscribers(){
// get affected CIs
var affectedCIs = new GlideRecord('task_ci');
affectedCIs.addQuery('task',current.sys_id);
affectedCIs.query();

var allPersons = [];

while(affectedCIs.next()){
var persons = [];
allPersons = allPersons.concat(getRelatedPersons(affectedCIs.ci_item.sys_id, persons));
}

allPersons = eliminateDuplicates(allPersons);
allPersons = allPersons.toString();

return allPersons;
}

function getRelatedPersons(ci_sys_id, persons){
var relPersons = new GlideRecord('cmn_notif_message');
relPersons.addQuery('configuration_item', ci_sys_id);
relPersons.query();

while (relPersons.next()) {
persons.push(relPersons.user.sys_id.toString());
}
var rel = new GlideRecord('cmdb_rel_ci');
rel.addQuery('child', ci_sys_id);
rel.query();
while (rel.next()) {
var parentSysID = rel.parent;
// get Interested Parties for parent CIs
getRelatedPersons(parentSysID, persons);
}
return persons;
}

function eliminateDuplicates(arr) {
// remove duplicates from array
var i, len=arr.length, out=[], obj={};

for (i=0;i < len;i++) {
obj[arr[i]]=0;
}
for (i in obj) {
out.push(i);
}
return out;
}

function notifyParents(table, itemSysID) {
var rel = new GlideRecord('cmdb_rel_ci');
rel.addQuery('child', itemSysID);
rel.query();
while (rel.next()) {
var parentSysID = rel.parent;
var parentName = rel.parent.getDisplayValue();
if (!noNotify[parentSysID]) {
count ++;
gs.log('### Notifying subscribers of ' + parentName);
noNotify[parentSysID] = true;
gs.eventQueue('ci.affected', current, parentSysID, parentName);
notifyParents('cmdb_ci', parentSysID);
}
}
}

2) Register a new event in the event registry called ‘task.notify.subscribers’
3) Create a new email notification that is triggered by the ‘task.notify.subscribers’ event. I used the following parameters for my notification:
-Name: Notify CI subscribers
-Event name: task.notify.subscribers (or whatever you call your event)
-Table: change_request
-User: event.parm2
-Subject:

A CI you have subscribed to is being impacted by change ${number} - ${short_description}

-Message:

${URI}
Short description: ${short_description}

Affected CIs: (Please note that the CIs listed below are only those that are directly impacted by the change request.  The CI you subscribed to may be impacted as a result of impact to one or more of the CIs listed below.

<mail_script>
   var affectedCIs = new GlideRecord('task_ci');
   affectedCIs.addQuery('task',current.sys_id);
   affectedCIs.query();

  while(affectedCIs.next()){
    template.print(affectedCIs.ci_item.getDisplayValue() + '\n');
  }
</mail_script>
By | 2018-07-09T15:37:35+00:00 January 8th, 2010|Categories: Email Notifications, Scripting|Tags: , |6 Comments

About the Author:

Mark has worked in the IT industry since 2002 and with ServiceNow since 2007. He is the founder and creator of SN | Guru and the co-founder of Crossfuze, one of the worlds leading ServiceNow consulting partners. Prior to co-founding Crossfuze, he worked for ServiceNow as a Senior Architect on the Professional Services team. He has personally led dozens of successful implementations encompassing every part of the ServiceNow platform. He is also responsible for designing and developing groundbreaking ServiceNow solutions and best practices in the form of various applications, turnkey solutions, and integrations during his tenure at ServiceNow, Crossfuze and, of course, SN | Guru. These solutions are used today by ServiceNow administrators and consultants alike in hundreds of ServiceNow instances around the world!

6 Comments

  1. alli January 11, 2010 at 11:25 pm - Reply

    As always, your posts here is very timely with my needs,

    Great work Mark, much appreciated

    with the 2nd question, what I did was just change the condition of the existing Affected ci notifications business rule to suit my needs.

  2. alli January 12, 2010 at 12:25 am - Reply

    I have implemented the first one and it looks great,

    one small thing to add though, since we have tons of CIs

    can you have a default filter in the CI list? so users won’t have to do the filtering on their own?

    • Mark Stanger January 13, 2010 at 10:30 am - Reply

      You can! Here’s an article that should help you out. It’s the same script that I used to set the filter in the image from this article.
      https://www.servicenowguru.com/scripting/client-sc

      • Vineeth August 8, 2011 at 11:42 pm - Reply

        Mark-For the 2nd question when you have created the User field.How should we pass the event.param2 to User Field? User field is a reference field and how we can pass the parameters then?

        • Mark Stanger August 9, 2011 at 7:15 am - Reply

          You collect those users in the business rule trigger and pass them in as an event parameter (as shown in step 2 above). Then you can access the value of that event parameter by using ‘event.parm2’ directly into the user field on the email notification record.

  3. vineeth August 9, 2011 at 11:58 am - Reply

    But the User field is a refernece field which expects a user id ? How can we pass the parameter to this field? Moreover the user field is not available when the notification is a subscribable one.

Leave A Comment