T

he primary mechanism in Service-now for transporting configuration changes between instances is the System Update Sets functionality. If you’ve worked with Service-now much at all, you’re familiar with this functionality and know that it can be a huge time saver. You also probably know that there are a few gotchas to update sets that can cause problems if you don’t pay attention to them. One of these gotchas is that not all changes you make in your instance get recorded in update sets. Of course, this is by design and it’s usually a good thing that saves you from problems. There are, however, some situations where you need to capture updates to a specific record in a table even though you don’t want all of the records in that table being captured. In this article I’ll show you a solution to this problem.

Manual Update Set Inclusion

First, let me give a couple of examples where this might come in handy…

Example 1

You need to modify the ‘Autoclose incidents’ Scheduled job to run once a day instead of once every hour. You can make this modification in your development instance, but it won’t be captured in an update set because the ‘sys_trigger’ table doesn’t have the ‘update_synch’ attribute set. There’s a great reason for this too. The last thing you want is for all of the records in the ‘sys_trigger’ table (SLA jobs, Inactivity monitors, Trend jobs, etc.) recording every update they ever make to an update set. You would end up with literally thousands of garbage updates in your update set in a matter of days just from normal system operations!

Until now, the solution to this problem was to export and import the file between instances as an added, manual step to your code migration process. It works (and in some cases may still be necessary), but it’s one more step that you would probably rather not have to think about.

Example 2

You’ve created a new table and application in your instance. The records in this table need to automatically receive a number when they are created so you create a new record in the ‘Number maintenance’ (‘sys_number’) table. There’s only one problem. Since the number maintenance table doesn’t include the ‘update_synch’ attribute those records won’t be included in your update set. Again, there’s a great reason for this. Number maintenance records get updated every single time you create a new task record, template, or software license. You don’t want all of that extra numbering garbage coming over to your production instance and messing things up there. All you want is to record the creation of a single Number maintenance record for your new table. Again, you’re forced to fall back on the manual export/import process to move that single record between instances.

The Solution:

PLEASE understand that this is in NO way a replacement for the out-of-box Update Sets functionality! The same guidelines recorded on the Service-now wiki for tracking customizations apply. This solution SHOULD NOT be used as a way to capture large amounts of data modifications that should be moved via import sets.

So here’s the way I came up with to fix this problem. Simply create a new UI action record as shown below on the table(s) that you need to record single-record updates on. Once you add the UI action, you can click the ‘Force to Update Set’ link on any record in that table to add it to your currently-selected update set. The UI action does three things…

  1. Check to make sure the current table isn’t already recording updates
  2. Push the current record into the currently-selected update set
  3. Reload the form and add an info. message indicating the addition
‘Force to Update Set’ UI Action
Name: Force to Update Set
Table: Wherever you need it!
Action name: force_update
Form link: True
Condition: gs.hasRole(‘admin’)
Script

//Commit any changes to the record
current.update();

//Check to make sure the table isn't synchronized already
var tbl = current.getTableName();
if(tbl.startsWith('wf_') || tbl.startsWith('sys_ui_') || tbl == 'sys_choice' || current.getED().getBooleanAttribute('update_synch') || current.getED().getBooleanAttribute('update_synch_custom')){
   gs.addErrorMessage('Updates are already being recorded for this table.');
   action.setRedirectURL(current); 
}
else{
   //Push the update into the current update set
   var um = new GlideUpdateManager2();
   um.saveRecord(current);

   //Query for the current update set to display info message
   var setID = gs.getPreference('sys_update_set');
   var us = new GlideRecord('sys_update_set');
   us.get(setID);

   //Display info message and reload the form
   gs.addInfoMessage('Record included in <a href="sys_update_set.do?sys_id=' + setID + '">' + us.name + '</a> update set.');
   action.setRedirectURL(current);
}

Forcing an update from a Background Script

In some cases, it might not be desirable to include a UI action to perform this function. In that case, you can run a script from the ‘Scripts – Background’ module to force the record into an update set. Just replace the table name and sys_id of the record in the script below.

//Query for the record
var rec = new GlideRecord('sys_number');
rec.get('973c8e8a9d022000da615b13b3a22f32');
//Push the record into the current update set  
var um = new GlideUpdateManager2();
um.saveRecord(rec);

Attachments can also be forced into an update set by including the attachment and attachment doc records. Just pass in the sys_id the same way. Thanks to John Andersen for the idea here. He’s created a script to add a full record and associated attachments all at once that you can find on his blog.

//Query for the record
var rec = new GlideRecord('sys_attachment');
rec.get('973c8e8a9d022000da615b13b3a22f32');
addAttachmentToUpdateSet(rec);

function addAttachmentToUpdateSet(attachmentGR) {
   var um = new GlideUpdateManager2();
   um.saveRecord(attachmentGR);

   var attdoc = new GlideRecord('sys_attachment_doc');
   attdoc.addQuery('sys_attachment', attachmentGR.sys_id);
   attdoc.orderBy('position');
   attdoc.query();
   while(attdoc.next()){
      um.saveRecord(attdoc);
   }
}