
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
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"!
Originally published on: 7-18-2016 08:01 AM
I updated the code and brought the article into alignment with my new formatting standard.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.