THURSDAY, JANUARY 19, 2017

Delete or Update Activity log and Journal Field Entries

S

erviceNow includes the ability to provide a full audit and journal history of records in the system. This is an extremely useful feature, but there are times when you need to override this audit process. Some examples may include a technician accidentally entering IT-only work notes into the customer facing ‘Additional comments’ field on an incident, or an end user supplying confidential information such as a password or social security number in a ticket.

Unfortunately, the process of deleting or updating audit, activity, or journal entries is fairly difficult to perform, and even more difficult to remember. The customization shown here makes this process much simpler by leveraging UI actions in the standard ‘History -> List’ view from any audited record.

Update ServiceNow Audit History

First, a little technical perspective as to why this solution is helpful. Without this solution, you would need to go to two or three separate tables (sys_audit, sys_history_line, and sys_journal_field) and update or delete entries. While doing this, you would need to be extremely careful about how you query the information since all three tables can be very large and accessing them incorrectly could bring your system to its knees. You would also need to know exactly what you were looking for and be cautious about where you clicked so that you didn’t ruin audit entries in the process.

This solution provides a single, consistent UI action-driven method that keeps you out of the audit tables and updates all of the necessary places in one click. It also includes a confirmation dialog to prevent accidental updates.

WARNING: It should go without saying that you should exercise extreme care when dealing with audit or journal entries in the system. Only make modifications in these areas if it’s absolutely necessary, and only do so within your organization’s change management process.

Delete audit/journal entries

Deleting audit or journal entries can be accomplished by adding a new UI action with the following settings.

‘Delete History Line’ UI Action
Name: Delete History Line
Table: History [sys_history_line]
Action name: delete_history_line
Show insert: false
Show update: true
Client: true
Form button: true
Onclick: confirmDelete()
Condition: gs.hasRole(‘admin’)
Script:

function confirmDelete(){
   if(confirm('Are you sure you want to permanently delete this history line and all corresponding audit history?\n\nTHIS ACTION CANNOT BE UNDONE!')){
      //Call the UI Action and skip the 'onclick' function
      gsftSubmit(null, g_form.getFormElement(), 'delete_history_line'); //MUST call the 'Action name' set in this UI Action
   }
   else{
      return false;
   }
}

//Code that runs without 'onclick'
//Ensure call to server-side function with no browser errors
if(typeof window == 'undefined')
   deleteHistoryLine();

function deleteHistoryLine(){
   var fieldVal = current["new"];
   var fieldName = current.field;
   
   //Query for and delete the 'sys_audit' record
   var aud = new GlideRecord('sys_audit');
   aud.addQuery('documentkey', current.set.id);
   aud.addQuery('fieldname', fieldName);
   aud.addQuery('newvalue', fieldVal);
   aud.query();
   if(aud.next()){
      aud.deleteRecord();
   }
   
   //Query for and delete the 'sys_journal_field' record (if applicable)
   var je = new GlideRecord('sys_journal_field');
   je.addQuery('element_id', current.set.id);
   je.addQuery('element', fieldName);
   je.addQuery('value', fieldVal);
   je.query();
   if(je.next()){
      je.deleteRecord();
   }
   
   //Set redirect and info message for the parent record
   gs.addInfoMessage(current.label + " entry '" + fieldVal + "' deleted.");
   action.setRedirectURL(current.set.getRefRecord());
   
   //Delete the 'sys_history_line' record
   current.deleteRecord();
}

Update audit/journal entries

In order to update audit or journal entries through the ‘sys_history_line’ table, you need to open up security a bit so that you can change the ‘New’ field value. This can be easily accomplished by creating a new ‘write’ ACL on the ‘History [sys_history_line]’ table and the ‘New’ field. This ACL should limit the ‘write’ operation to the ‘admin’ role using the related list at the bottom of the ACL form.

Once you’ve opened up the security for the ‘New’ field, you can add the following UI action settings in the same way as the ‘Delete History Line’ UI action above.

‘Update History Line’ UI Action
Name: Update History Line
Table: History [sys_history_line]
Action name: update_history_line
Show insert: false
Show update: true
Client: true
Form button: true
Onclick: confirmUpdate()
Condition: gs.hasRole(‘admin’) && current[“new”].canWrite()
Script:

function confirmUpdate(){
   if(!g_form.getControl('new').changed){
      alert("Please enter a new value into the 'New' field.");
      return false;
   }
   if(confirm('Are you sure you want to permanently update this history line and all corresponding audit history?\n\nTHIS ACTION CANNOT BE UNDONE!')){
      //Call the UI Action and skip the 'onclick' function
      gsftSubmit(null, g_form.getFormElement(), 'update_history_line'); //MUST call the 'Action name' set in this UI Action
   }
   else{
      return false;
   }
}

//Code that runs without 'onclick'
//Ensure call to server-side function with no browser errors
if(typeof window == 'undefined')
   updateHistoryLine();

function updateHistoryLine(){
   var fieldVal = current["new"];
   var fieldName = current.field;
   var fieldLabel = current.label.toString();
   var setID = current.set.id.toString();
   
   //Query for and update the 'sys_audit' record
   var aud = new GlideRecord('sys_audit');
   aud.addQuery('documentkey', current.set.id);
   aud.addQuery('fieldname', fieldName);
   aud.addQuery('internal_checkpoint', current.internal_checkpoint);
   aud.query();
   if(aud.next()){
      aud.newvalue = fieldVal;
      aud.update();
   }
   
   //Query for and update the 'sys_journal_field' record (if applicable)
   var je = new GlideRecord('sys_journal_field');
   je.addQuery('element_id', current.set.id);
   je.addQuery('element', fieldName);
   je.addQuery('sys_created_on', current.update_time);
   je.query();
   if(je.next()){
      je.value = fieldVal;
      je.update();
   }
   
   //Refresh the history set
   if(typeof GlideHistorySet != 'undefined')
      GlideHistorySet(current.set.id.getRefRecord()).refresh();
   else
      Packages.com.glide.audit.HistorySet(current.set.id.getRefRecord()).refresh();  
   //Set redirect and info message for the new set record
   var newSet = new GlideRecord('sys_history_set');
   newSet.get('id', setID);
   gs.addInfoMessage(fieldLabel + " entry '" + fieldVal + "' updated.\nIf audit history list is empty, return to the parent record and select 'History -> List' to regenerate.");
   action.setRedirectURL(newSet);
}

Once the configuration above has been applied, users with the ‘admin’ role can navigate to the history of the record by right-clicking the record form header and clicking ‘History -> List’. Then, simply open the history record to modify and delete or update accordingly!

19 Comments

Manuel Panman 14-02-2013, 05:27

Can’t you just go to History > List
select the comment you want to delete and choose list-action > Delete?
Works fine for me
What I mean is: It Seems to me this option already is available in the instance itself. Maybe it came with a recent patch of release? I already have a UI action delete available in the incident > history > list

Reply
Mark Stanger 14-02-2013, 06:13

I think you must be seeing something else then. If you check out a ServiceNow demo instance running the latest code, no such UI action is available. Also, you might want to make sure that your history line doesn’t get regenerated as it’s just generated on the fly from the true audit data. You can test this by deleting the entire history set, then regenerating it by navigating through ‘History -> List’ again. I’m guessing even if you did manage to delete it, it will come back again because the audit and journal values haven’t been deleted. If it doesn’t, then you may have a solution that nobody else has built into your instance.

Reply
Manuel Panman 22-02-2013, 08:34

I tried to delete a note by using History > list > Delete (ui action)
There is no way that it will come back.

When I navigate through History>list again it’s still deleted.

Maybe someone implemented you’re solution already in our instance. When I go to the demo instance there is now way I can delete history lines like I do in our instance. We didn’t ever asked for this option specificly so for me it’s a mystery why we have this option. Knowing know it’s not a out-of-the-box feature I think it should be this simple like you created it to be. Good job.

Reply
mark sandner 09-04-2013, 13:54

I just ran through deleting an entry from the history list. But the entry still viewable in the journal and audit lists. But if you just want it removed from public view, this seems to be fine…I think….

Reply
Kurt Lutz 09-03-2013, 23:16

What if the audit entry is an email? We have had cases where data like a password was placed in there and sent. Could a query / delete be added to this for the sys_email table?

Also, does this work on berlin? I tried the code there (for the update) and it says it updates but when you look at the entry – it reverts back to its prior entry it does not keep the update.

Reply
Mark Stanger 11-03-2013, 16:53

Email audit entries can be queried and deleted from the ‘sys_email’ table. You could add a defined related list to show those in the history set form if you wanted easier access. Updates only work for journal entries since the other fields can be updated and/or deleted directly.

Reply
Kurt 11-03-2013, 17:30

Thank you Mark.

Reply
Mark Sandner 09-04-2013, 12:52

I have been doing this quite a few times recently, and it has been a multi step process:
1. Get the sys_id of the task
2. Get the audit_sysid of the exact entry you want to delete by going to History and click through the specific entry
3. Delete 3 entries using the following url’s:
a. Use sys_id: yourinstance.service-now.com/sys_journal_field_list.do?sysparm_query=element_id=sys_id from step 1
b. Use sys_id: yourinstance.service-now.com/sys_audit_list.do?sysparm_query=documentkey=sys_id from step 1
c. Use audit_sys_id: yourinstance.service-now.com/sys_history_line_list.do?sysparm_query=sys_id from step 2
4. Last Step:Right-click the form header, and select History –> List.
Delete the “Record History” record you are taken to.

So, I am glad to see that I should be able to accomplish the same results with A ui action. Thanks Mark

Reply
Dave Richter 23-09-2013, 11:10

When we have a situation that a user cannot see the details of a task history and I as an admin can, I have successfully deleted the history record from the history->list (using the task sysid in the URL ) and when the system recreates it the user can then see that history detail.

I now have a situation where a user record had the incorrect name for a brief while, and after it was brought to my attention and corrected there was a task that had an activity log entry from several months ago from work done by that user which had the incorrect name when viewed by a caller. When viewed by myself, the name was correct.

If I delete that history record and let the system re-create it will it also resolve this issue ?

Thank you.

Reply
Mark Stanger 23-09-2013, 11:44

History records can be deleted and recreated without issue so what you’re saying should work. The important piece (that cannot be recreated) is the ‘sys_audit’ entry that serves as the basis for the history line entries. Just make sure that the ‘sys_audit’ entry accurately reflects what you want to have displayed and then you should be safe to delete and recreate the history lines.

Reply
Jim Uomini 08-01-2014, 14:05

Highly useful. Thanks much Mark.

Reply
Mark Laucus 17-09-2014, 10:16

This is a useful tool. Just as stated above sometimes information is added that should not be in a case and this will help those times. I also agree with there should be a strict change management process before performing this action.

Reply
Dan 25-09-2014, 12:18

Is this meant to exclusively be for journal fields then? For the Update History Line UI action – it doesn’t appear to work for non journal fields. For journal fields it will update the journal entry appropriately and history. I was looking for the same behavior on both the new and old fields actually for fields like short description or description on the history line.

Reply
Mark Stanger 25-09-2014, 17:21

This should work for any entry regardless of field type.

Reply
Larry Robinson 19-01-2015, 19:19

I found your posting helpful in a different application. I am trying to import incident records from a home grown Remedy application and I an having some trouble crafting my sys_audit entries so that the system recognizes them. I believe it may have something to do with the value of the “Record internal checkpoint” field. Can you tell me how this value is generated and how I can generate valid values?

Thanks.
Larry

Reply
Mark Stanger 21-01-2015, 09:39

I’m not sure on that one Larry. That’s all buried code that generates that value so I’m not even aware of how to get to it.

Reply
Del 16-04-2015, 02:02

I have implemented this in our Fuji version of ServiceNow and its not working. Button appears, allows me to update and the correct confirmation message appears. But when I submit (modify or delete) the original version is still stored.

Reply
Dave Stuart 05-05-2016, 12:22

Del,

Interesting. It’s working fine on my Fuji instance, once I got all the right boxes checked.

Reply
Martha 13-12-2016, 10:22

Hi – we are trying to implement this as part of a merge of companies/systems.
As part of this we need to edit the created date of the audit record to ensure the activity formatter shows work notes in the correct order. We can change any other field (EG. User) and it is correctly shown in the formatter, but as soon as we touch the date the activity is generated with the creation information of the incident.
Has anyone managed to get this to work? Any ideas why we can’t change the date?
Thanks.

Reply

Leave a Reply


Latest Comments

  • David: It appears that I can hit sys_properties table with REST. This works, but I haven’t yet discovered the...
  • Mark Stanger: Hey David, It doesn’t surprise me that scoped apps have made this more difficult. I’m not...
  • David: Mark, do you have an example of how to do this in a scoped app? It seems there are many hoops to jump through...
  • Mark Stanger: The only possibility is to create a system property to override this in your application. Check out the...