sabell2012
Mega Sage
Mega Sage

NOTE: MY POSTINGS REFLECT MY OWN VIEWS AND DO NOT NECESSARILY REPRESENT THE VIEWS OF MY EMPLOYER, ACCENTURE.

 

DIFFICULTY LEVEL:    ADVANCED
Assumes having taken the class SSNF and has good intermediate to advanced level of knowledge and/or familiarity with Scripting in ServiceNow.


Some time ago I wrote on this topic (Where Does All The Code Hide? - 9/14/2013), where I attempted to identify all of the possible places that code could reside inside of the ServiceNow platform. That was ten-plus years ago, and the platform has come a long way since then! At that time I used a somewhat manual process to pull together a list of variables that were of a particular type:

 

  • Script
  • XML
  • HTML
  • Condition

 

and so on.   It took me a bit to assemble the whole thing, but I found that the result was remarkable. In 2013 there were 187 possible locations! In 2016 there 359. In 2023? Well, let's see...

 

I have become somewhat more sophisticated in my approach these days. Here is a coding example of how to dissect the sys_dictionary table to obtain the list. I thought I would share a bit of that to give you an idea where this could be taken.  

 

I have included several interesting techniques and best practices while working with the GlideRecord object that you might find of interest.

 

var listOfFieldsToCheck = ['script', 'xml', 'html', 'html_script', 'script_plain', 'html_script', 'conditions', 'variable_conditions', 'condition_string'];
var listOfDoesNotContain = ['var__', 'bsm_', 'log', 'metric', 'ecc', 'clone', 'content_', 'sys_update_', 'u_'];
var message = '--->Script Location List\n';
var scriptLocationList = buildScriptLocationList(listOfFieldsToCheck, listOfDoesNotContain);

message += '---> scriptLocationList.length: ' + scriptLocationList.length + '\n';

for (var i=0; i < scriptLocationList.length; i++) {
	message += gs.getMessage('{0} - {1} - {2}\n',
		[scriptLocationList[i].table, 
		scriptLocationList[i].column_name, 
		scriptLocationList[i].type]);
}
gs.info(message);

message = '\n\n--->Exception Location List\n';
var exceptionLocationList = buildExceptionLocationList(listOfDoesNotContain);
message += '---> exceptionLocationList.length: ' + exceptionLocationList.length + '\n';

for (var i=0; i < exceptionLocationList.length; i++) {
	message += gs.getMessage('{0} - {1} - {2}\n',
		[exceptionLocationList[i].table, 
		exceptionLocationList[i].column_name, 
		exceptionLocationList[i].type]);
}
gs.info(message);

function buildScriptLocationList(listOfFieldsToCheck, listOfDoesNotContain) {
	var scriptLocations = new GlideRecord('sys_dictionary');
	
	// what fields do we want to check for?
	scriptLocations.addQuery('internal_type.name', 'IN', listOfFieldsToCheck);
	
	// tables we want to exclude
	for (var j=0; j < listOfDoesNotContain.length; j++) {
		scriptLocations.addQuery('name', 'DOES NOT CONTAIN', listOfDoesNotContain[j]);
	}
	
	// this is how you do multiple order bys with a gliderecord
	scriptLocations.orderBy('name').orderBy('element');
	scriptLocations.query();

	scriptLocList = [];

	while(scriptLocations.next()) {
		var scriptLocation = {};
		scriptLocation.table = scriptLocations.getValue('name');
		scriptLocation.column_name = scriptLocations.getValue('element');
		scriptLocation.type = scriptLocations.getValue('internal_type');
		scriptLocList.push(scriptLocation);
	}
	
	return scriptLocList;
}

function buildExceptionLocationList(listOfDoesNotContain) {
	// this is a best practice for allowing your encoded query to be easier to maintain
	var sql = 'internal_type=string' +
		'^elementNOT LIKEdescript' +
		'^elementNOT LIKEsubscript' +
		'^elementNOT LIKEjavascript' +
		'^elementNOT LIKEcondition_type' +
		'^elementLIKEscript' +
		'^ORelementLIKEcondition' +
		'^ORelementLIKEhtml' +
		'^ORelementLIKExml';

	var exceptionLocations = new GlideRecord('sys_dictionary');
	exceptionLocations.addEncodedQuery(sql);
	for (j=0; j < listOfDoesNotContain.length; j++) {
		exceptionLocations.addQuery('name', 'DOES NOT CONTAIN', listOfDoesNotContain[j]);
	}
	exceptionLocations.orderBy('name').orderBy('element');
	exceptionLocations.query();
	exceptionLocList = [];
	while(exceptionLocations.next()) {
		var exceptionLocation = {};
		exceptionLocation.table = exceptionLocations.getValue('name');
		exceptionLocation.column_name = exceptionLocations.getValue('element');
		exceptionLocation.type = exceptionLocations.getValue('internal_type');
		exceptionLocList.push(exceptionLocation);
	}
	
	return exceptionLocList;
}

 

Some GlideRecord Notes:

 

You can:

1. Use an array with the IN statement to act as an "OR" condition.

2. Dynamically add extra conditions based on an array.

3. Stack .orderBy statements to do more sophisticated ordering of the data (<--- this should have worked and did not - investigating)

 

And:

4. Demonstration of how an Encoded Query can be ordered to provide better maintenance.

 

I created a Fix Script to execute the code. Executing brought back the following results:

 

*** Script: --->Script Location List
---> scriptLocationList.length: 718
agent_assist_recommendation - script - script
agent_schedule_task_config - task_filter - conditions
agent_schedule_task_config - script - script
aisa_ui_action - ui_action_visibility_script - script
aisa_ui_action - result_table_condition - conditions
ais_acl_overrides - script - script_plain
ais_acl_overrides - condition_script - script_plain
ais_datasource - filter - conditions
ais_genius_result_configuration - script - script_plain
ais_rule - trigger - conditions
ais_search_source - condition - conditions
alm_asset_ci_field_mapping - asset_mapping_condition - conditions
alm_asset_ci_field_mapping - ci_mapping_condition - conditions
alm_license - assigned_condition - conditions
alm_license - entitlement_condition - conditions
asmt_condition - condition - conditions
automation_pipeline_transformer_javascript - script - script
awa_inbox_layout - condition - conditions
awa_inbox_layout - card_layout - html
awa_queue - condition - conditions
awa_queue - condition_script - script
awa_service_channel - utilization_condition - conditions
awa_service_channel - condition - conditions
awa_work_item_sizing - condition - conditions
awa_work_item_sizing - condition_script - script
cab_attendee - email_content - html
cab_definition - change_condition - conditions
... vtb_board - filter - conditions v_formatted_schedule_report - html_report - html wf_activity_definition - script - script_plain wf_condition - condition - condition_string wf_condition_default - condition - condition_string wf_element_activity - input_process_script - script wf_element_activity - processing_script - script wf_element_activity - output_process_script - script wf_workflow_version - condition - conditions wf_workflow_version - on_cancel - script

Wow, 718 (Vancouver). Was 359 in July of 2016. ServiceNow has significantly grown their coding presence in the last seven years!

 

If you scroll further down you will see that there were 94 results in the Exception List (59 in 2016). These are worthy of investigating, if you want, to see if they truly contain script. These will be string fields that contain code. Ugly. The ones labeled with Script should probably be Script fields as, at the very least, to be able to utilize the Script editor.

 

--->Exception Location List
---> exceptionLocationList.length: 94
ais_genius_result_configuration - trigger_condition - string
awa_queue - condition_mode - string
awa_work_item_sizing - condition_mode - string
cert_cond - condition_display - string
change_risk_details - risk_condition_risk - string
change_risk_details - risk_condition_impact - string
change_risk_details - risk_condition_risk_prev - string
change_risk_details - risk_condition_impact_prev - string
cmdb_ci_db_hbase_instance - site_xml - string
cmdb_ci_endpoint_sim_flow - xml_url - string
cmdb_ci_endpoint_sim_inc - xml_url - string
cmdb_ci_kvm - details_xml - string
cmdb_ci_kvm_network - details_xml - string
cmdb_ci_kvm_object - details_xml - string
cmdb_ci_kvm_storage_pool - details_xml - string
cmdb_ci_kvm_storage_volume - details_xml - string
cmdb_ci_kvm_vm_instance - details_xml - string
cmdb_kvm_device - details_xml - string
cmn_notif_service_provider - construction_script - string
cmn_notif_service_provider - script - string
cmn_rota_escalation - script_name - string
cmn_schedule_page - header_html - string
discovery_probe_parameter - value_script - string
expert_panel_redirect - script - string
gs_entitlement_plugin_mapping - condition_fields - string
gs_entitlement_plugin_mapping - condition_script - string
interaction - internal_transcript - string
interaction - transcript - string
kb_navons - script - string
pa_thresholds - condition - string
pa_widgets - cutoff_condition - string
risk_conditions - script_values - string
sc_cat_item_delivery_plan - script - string
sc_ic_aprvl_type_defn - script_output - string
sc_ic_aprvl_type_defn_staging - script_output - string
sn_cloud_discovery_retry_configuration - script - string
...

 

So, since 2016 I have ferreted out where even more code is hiding. Take a look at the following code. This pulls from a VERY little known table: sys_variable_value, which contains the scripts for Workflow Activities, Flow Designer Actions, and a lot of other hard-to-locate scripts:

 

// Script hidden table
var variableRecords = new GlideAggregate('sys_variable_value');
variableRecords.addAggregate('COUNT','variable');
variableRecords.groupBy('document');
variableRecords.orderBy('document');
variableRecords.groupBy('variable');
variableRecords.orderBy('variable');
variableRecords.query();

while (variableRecords.next()) {
	var variableName = variableRecords.variable.getDisplayValue().toLowerCase();
	if (variableName.indexOf('script') > -1 && variableName.indexOf('description') == -1 && variableName.indexOf('subscription') == -1) {
		var tableName = variableRecords.document.getDisplayValue();
		var scriptVariableCount = variableRecords.getAggregate('COUNT','variable');
		gs.info('---> table name: {0}, count: {1} - {2}', [tableName, scriptVariableCount, variableName]);
	}
}

 

For my instance this results in:

 

*** Script: ---> table name: sys_atf_step, count: 132 - test script
*** Script: ---> table name: sys_hub_step_instance, count: 20 - mid server script
*** Script: ---> table name: sys_hub_step_instance, count: 4 - script
*** Script: ---> table name: sys_hub_step_instance, count: 969 - script
*** Script: ---> table name: sys_hub_step_instance, count: 20 - script path
*** Script: ---> table name: wf_activity, count: 1 - additional approvers script
*** Script: ---> table name: wf_activity, count: 20 - additional approvers script
*** Script: ---> table name: wf_activity, count: 7 - additional groups script
*** Script: ---> table name: wf_activity, count: 1 - additional groups script
*** Script: ---> table name: wf_activity, count: 16 - advanced script
*** Script: ---> table name: wf_activity, count: 19 - advanced script
*** Script: ---> table name: wf_activity, count: 7 - advanced script
*** Script: ---> table name: wf_activity, count: 20 - approval script
*** Script: ---> table name: wf_activity, count: 7 - approval script
*** Script: ---> table name: wf_activity, count: 59 - condition script
*** Script: ---> table name: wf_activity, count: 16 - due date script
*** Script: ---> table name: wf_activity, count: 19 - due date script
*** Script: ---> table name: wf_activity, count: 18 - due date script
*** Script: ---> table name: wf_activity, count: 7 - due date script
*** Script: ---> table name: wf_activity, count: 2 - finished script
*** Script: ---> table name: wf_activity, count: 19 - script
*** Script: ---> table name: wf_activity, count: 143 - script
*** Script: ---> table name: wf_activity, count: 76 - script
*** Script: ---> table name: wf_activity, count: 37 - to (script)

That is a lot of hidden scripts. I recently z-booted my PDI so this is pretty close to OOB. I'll bet on a much older instance you will see a significant increase in these numbers!

 

So both scripts, overall, are probably not a comprehensive list, and it would be worthy of extra exploring, but you get the general idea: There are a LOT of different places where code can exist inside the ServiceNow platform!

 

Enjoy!

Steven Bell.

 

If you find this article helps you, don't forget to log in and mark it as "Helpful"!

 

sabell2012_0-1699913273154.png


Originally published on: 7-18-2016 08:01 AM

I updated the code and brought the article into alignment with my new formatting standard.

2 Comments