Instance Scan "Data" Scan Check examples - ServiceNow Community
Mark Roethof
Tera Patron
Tera Patron

Articles, Blogs, Videos, Podcasts, Share projects - Experiences from the field

 

Hi there,

 

When talking about Instance Scan, mostly mentioned for setting up Scan Checks is about performing checks on code, certain settings on Business Rules / Client Scripts / Script Includes, etcetera. Though why limit ourselves to only best practices on the coding front? Instance Scan has a really powerful scan engine, with which you can interrogate your instance on way more.


Data

In this article I'll share some examples of Scan Checks which you could use for a "Data" suite. Data checks which you could perform regularly on a Production instance. For example weekly, to support the activities of a System Administrator. Obviously these checks can bring data issues to the surface which need to be corrected, though the question could also be why are those data issues occurring? Maybe there's some scripting issue or integration issue going on, or a System Administrator who incorrectly performed some manual actions, etcetera.


Data examples

Table Check: Active approval for inactive task

Category
Manageability

Description
Approvals for inactive tasks indicate a process error or a technical error. Tasks should not proceed when approvals are still open or only canceled. If canceled, active approvals should be too.

Table
sysapproval_approver

Condition
sysapproval.active=false^stateINnot requested,requested


Table Check: Active Notifications with inactive recipient Users

Category
Manageability

Description
Validate that all notifications are configured with active users if there are any defined under the "Users" field.

Documentation
https://docs.servicenow.com/csh?topicname=t_CreateANotification.html&version=latest

Table
sysevent_email_action

Condition
active=true^recipient_usersISNOTEMPTY

Script

(function (engine) {

	// Define variables
	var regex = /[0-9a-f]{32}/g;
	var recipients = engine.current.recipient_users.split(',');

	var l = recipients.length;
	for(var i = 0; i < l; i++) {
		if(recipients[i].match(regex)) {
			var getUser = new GlideRecord('sys_user');
			getUser.addQuery('sys_id', recipients[i]);
			getUser.addQuery('active', false);
			getUser.setLimit(1);
			getUser._query();

			// Create scan finding
			if(getUser.hasNext()) {
				engine.finding.increment();
				return;
			}
		}
	}

})(engine);


Table Check: Active Users with inactive Manager

Category
Manageability

Description
Validate that all users are configured with an active user if there is any defined under the "Managers" field.

Documentation
https://docs.servicenow.com/csh?topicname=c_UserAdministration.html&version=latest

Table
sys_user

Condition
active=true^manager.active=false


Table Check: Active Workflow Context with Inactive Parent

Category
Manageability

Description
Workflows are generally run during the lifecycle of a record. When the record reaches a closed state, the Workflow should be finished. Still running Workflows might indicate an issue in your environment, for example the Workflow itself, related scripting, etc..

Table
wf_context

Condition
active=true

Script

(function (engine) {

	// Query record 
	var getRecord = new GlideRecord(engine.current.getValue('table'));
	getRecord.addQuery('sys_id', engine.current.getValue('id'));
	getRecord.addQuery('active', false);
	getRecord.setLimit(1);
	getRecord._query();

	// Create scan finding
	if(getRecord._next()) {
		engine.finding.increment();
	}

})(engine);


Table Check: Orphan Incident Tasks

Category
Manageability

Description
Incident Tasks that are not associated with an Incident will most likely never be seen and modified. Every Incident Task should have a parent Incident as they always should be a part of an Incident.

Table
incident_task

Condition
active=true^incidentISEMPTY


GitHub example-instancescan-checks

The example Linter Checks mentioned in this article can also be found on the "example-instancescan-checks" GitHub repository. Also other Scan Checks can be found there which have been contributed by several people. 

---


And that's it actually. Hope you like it. If any questions or remarks, let me know!

 

C

If this content helped you, I would appreciate it if you hit bookmark or mark it as helpful.

 

Interested in more Articles, Blogs, Videos, Podcasts, Share projects I shared/participated in?
- Articles, Blogs, Videos, Podcasts, Share projects - Experiences from the field

 

Kind regards,


Mark Roethof

ServiceNow Technical Platform Architect @ Quint Technology

2x ServiceNow Developer MVP

2x ServiceNow Community MVP

---

LinkedIn

Comments
Maik Skoddow
Tera Patron
Tera Patron

Hi @Mark Roethof ,

to my opinion, your scan check "Active Workflow Context with Inactive Parent" has an error.

You assume that a Workflow Context only references a record that has an "active" field, which is not true. For this reason, it must first be checked whether the corresponding table has this field before a query for "active=true" can be executed.

I also added another check, because I saw that there are active Workflow Contexts, which do not reference a Record and are therefore orphaned.

(function (engine) {

  if (engine.current.getValue('id') == null || engine.current.getValue('table') == null) {
    engine.finding.increment();
  }
  else {
    //Check wether the related record has an "active" field of type boolean
    var grActiveCheck = new GlideRecord(engine.current.getValue('table'));

    grActiveCheck.initialize();

    var intSize        = grActiveCheck.getElements().size();
    var arrFields      = grActiveCheck.getElements(); 
    var hasActiveField = false;

    for (var i = 0; i < intSize && !hasActiveField; i++) {
      var glideElement = arrFields.get(i); 
      var strFieldName = glideElement.getName().toString();
      var strFieldType = glideElement.getED().getInternalType().toString();

      hasActiveField = strFieldName == 'active' && strFieldType == 'boolean';
    }

    if (hasActiveField) {
      grActiveCheck.addQuery('name', engine.current.getValue('table'));
      grActiveCheck.addQuery('element', 'active');
      grActiveCheck.query();

      if (grActiveCheck.next()) {
        // Query record 
        var grRelatedRecord = new GlideRecord(engine.current.getValue('table'));

        grRelatedRecord.addQuery('sys_id', engine.current.getValue('id'));
        grRelatedRecord.addQuery('active', false);
        grRelatedRecord.setLimit(1);
        grRelatedRecord._query();

        // Create scan finding
        if (grRelatedRecord._next()) {
          engine.finding.increment();
        }
      }
    }
  }

})(engine);

Kind regards
Maik

Mark Roethof
Tera Patron
Tera Patron

Hi Maik,

Will look into your remark about the active part. Tnx.

On purpose I did not check for workflow context without a (valid) parent. I've got a different check for that. A different check because such a situation should not exist in production instances and should be investigated by a System Administrator.

Kind regards,
Mark

Version history
Last update:
‎08-14-2024 12:57 PM
Updated by:
Contributors