The CreatorCon Call for Content is officially open! Get started here.

Wybren1
Tera Guru

Introduction

One of the challenge we face in ServiceNow working within a MSP company is integrating with multiple applications, while this is not really the challenge. The challenge comes in the habit of creating new fields for each ID needed within the Task, Company or User table ending up with way too many fields.

System property can be an option but this will also be ending up with way too much records in my opinion.

Another option could be using the import table but this needs to be created for 'each' integration, and not always an option.

Solution

My solution to the above challenge is creating one table that will containing ALL the ID's, the record will serve as a 'link' between the objects from integrated applications and ServiceNow records.

Especially with the IntegrationHub getting more and more usage. I've found this the most flexible in every way.

The name I've come up with is the 'Integration Link'

Integration Link (Table)

find_real_file.png

So I've created 4 fields in the Table:

  • Application: This is a choice list of which application it will be (example: Jira, SAP, Cisco Meraki)
  • Instance & Target Table: This is a Document ID with the ability to point to any records in ServiceNow
  • Integration Link ID: The ID of the external application needed for the correct 'link' to get things working

How does this help?

Every integration is always in need of a 'ID' like ServiceNow used SysID to link an object, while searching for a user by email or username can be an option but pretty inefficient and unreliable based on information used. It's just better to create a 'Integration Link' point to the correct sys_user - GlideRecord with the ID from the integration, even given you the option to use 'getRefRecord'.

While you have the option to create a field within the User Table, one field is most probably not enough.
For example:

  • GUID (Active directory)
  • accountId (Atlassian)
  • id or userPrincipalName (Office365)
  • id (Cisco Meraki)
  • IDs or URNs (LinkedIn)
  • sysID (ServiceNow, maybe another ServiceNow instance) 

How does it work?

Seeing the above examples needed for only the user table, imagine the company, task or even the cmdb_ci table.

The magic part comes from the 'application' choice list in combination with the ID, being a choice list you can also create 'sub' application for the same integration.

find_real_file.png

Integration Record example:

find_real_file.png

Zabbix works for instance with CI's in combination with organisations, having the ability to add ID's needed for a correct integrations WITHOUT adding another field on the CI record will help in my opinion in the end.

Closing notes

Hope this helps! Suggestions are always welcome.

If people really like this solution I can create an XML to 'Share' in ServiceNow including:

  • Integration Table
  • Flow designer actions
  • Script Include
  • Some Basic Relations for the User table and Company table to get you started

Scripts

For now here's the script include;

var IntegrationLinkAPI = Class.create();
IntegrationLinkAPI.prototype = {
    initialize: function() {
		this.setIntegrationLink = true;
		this.verbose = false;
    },
	
	/**SNDOC
	@name processIntegrationLink
	@description Checks all given information and creates a integration link

	@param {string} [application] - Application Value
	@param {string} [systemID] - The Integrated system unique ID
	@param {object} [recordGR] - GlideRecord to Link

	@example
	var linkIntegrate = new BNCIntegrationLinkAPI();
	linkIntegrate.procesIntegrationLink('applicationValue', 'systemID', recordGR);

	@returns {boolean} Wether it succeeded
	*/
	processIntegrationLink : function (application, systemID, recordGR) {
		
		this.debug('Start processing the link for ' + application + ' ID: ' + systemID + ' GlideRecord: ' + recordGR.getUniqueValue());
		
		if(!application) {
			this.debug('No application given, quitting');
			return false;
		}
		
		if(!systemID) {
			this.debug('No ID given, quitting');
			return false;
		}
		
		if(!recordGR.isValid()) {
			this.debug('Record given is not a valid GlideRecord, quitting');
			return false;
		}
		
		//Search if exists
		if(this.searchRecord(systemID, application, recordGR.getTableName())) {
			this.debug('Link already exists, quitting');
			return;
		}
		
		//Create new Link
		var createdLink = this._createIntegrationLink(application, systemID, recordGR);
		return createdLink;
	},
	
	/**SNDOC
	@name _createIntegrationLink
	@description Creates a record for the integration table
	@private

	@param {string} [application] - Application Value
	@param {string} [systemID] - The Integrated system unique ID
	@param {object} [recordGR] - GlideRecord to Link

	@returns {boolean} Returns if succeeded
	*/
	_createIntegrationLink : function (application, systemID, recordGR) {
		
		var linkGR = new GlideRecord('u_integration_link');
		linkGR.initialize();
		
		linkGR.u_application = application;
		linkGR.u_integration_id = systemID;
		linkGR.u_target_table = recordGR.getTableName();
		linkGR.u_instance = recordGR.getUniqueValue();
		
		if(linkGR.insert()) {
			this.debug('Created integration link for ' + application);
			return true;
		}
		
		return false;
	},
	
	/**SNDOC
	@name searchRecord
	@description Search for the ServiceNow Record

	@param {string} [uniqueID] - Unique Identifier for the record
	@param {string} [applicationName] - Name of the application for the integration
	@param {string} [tableName] - *Optional* the table in which it can find it, it will improve the speed

	@example
	var integrationLink = new BNCIntegrationLinkAPI();
	integrationLink.searchRecord('112', 'AccountView', 'task');

	@returns {GlideRecord} Returns the GlideRecord found
	*/
	searchRecord: function(uniqueID, applicationName, tableName) {
		
		this.debug('Searching record with ' + uniqueID + ' for ' + applicationName);
		
		var linkGR = new GlideRecord('u_integration_link');
		linkGR.addQuery('u_integration_id', uniqueID);
		linkGR.addQuery('u_application', applicationName);
		
		//If the table is given add the query
		if(tableName) {
			linkGR.addQuery('u_target_table', tableName);
		}
		linkGR.query();
		
		if(linkGR.hasNext()) {
			linkGR.next();
			
			if(!linkGR.hasNext()) {
				this.debug('One record found, returning');
				var recordToReturn = linkGR.u_instance.getRefRecord();
				return recordToReturn;
			} else {
				this.debug('Found multiple records, cannot return it. Try to resolve this issue by manually adjusting this');
				return;
			}
		} else {
			this.debug('Could not find a matching ID for '+ uniqueID + ' in ' + applicationName);
			return;
		}
		
	},
	
	//Debugging
	debug : function(msg) {
		if(this.verbose) {
			gs.log(msg, this.type);
		}
	},
	

    type: 'IntegrationLinkAPI'
};
Version history
Last update:
‎07-09-2019 12:09 PM
Updated by: