Article -> Detecting Duplicate Client Scripts Using a Background Script
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
yesterday - last edited 2 hours ago
Hi All, This is my first try at writing article here on the community, its about a Client Script Duplicate Audit script.
This background script identifies duplicate client scripts on specific tables such as incident, change_request, etc. Its goal is to find duplicate client scripts. Initially I thought to logic run on the sys_script_client table itself but the output was too cluttered, so to make it clearer, a target table variable was used to input TableName.
The script checks only active Client Scripts and compares key attributes like name, UI type, type (onLoad, onChange, onSubmit), order, and field (for onChange). Scripts sharing the same combination are grouped as duplicates, helping to detect duplicate client script.
var targetTable = 'change_request'; // < can be incident, change_request, wm_order, etc. >
var seen = {};
var duplicateCount = 0;
var totalCount = 0;
var clientAudit = new GlideRecord('sys_script_client');
clientAudit.addQuery('table', targetTable);
clientAudit.addQuery('active', true);
clientAudit.orderBy('sys_created_on');
clientAudit.query();
gs.print('--- Duplicate Client Script Audit for table: ' + targetTable + ' ---');
gs.print('Sorted by creation date (oldest → newest)');
gs.print('MODE: Detection only (no updates performed).');
gs.print('');
while (clientAudit.next()) {
totalCount++;
var key = clientAudit.name + '_' + clientAudit.ui_type + '_' + clientAudit.type + '_' + clientAudit.order;
if (clientAudit.type == 'onChange') key += '_' + clientAudit.field;
var info = clientAudit.name +
' | Type: ' + clientAudit.type +
(clientAudit.type == 'onChange' ? ' | Field: ' + clientAudit.field : '') +
' | Order: ' + clientAudit.order +
' | Created: ' + clientAudit.sys_created_on.getDisplayValue() +
' | Sys_id: (' + clientAudit.sys_id + ')';
if (!seen[key]) {
seen[key] = {
original: info,
duplicates: []
};
}
// If key already exists, put into duplicate
else {
seen[key].duplicates.push(info);
duplicateCount++;
}
}
var groupsWithDuplicates = 0;
for (var key in seen) {
var group = seen[key];
if (group.duplicates.length > 0) {
groupsWithDuplicates++;
gs.print(group.original);
var trimmedKey = key.split('_')[0];
gs.print('This ' + trimmedKey + ' script has ' + group.duplicates.length + ' duplicate' + (group.duplicates.length > 1 ? 's.' : '.'));
gs.print('--------------------------------------');
}
}
if (groupsWithDuplicates === 0) {
gs.print('No duplicate client scripts found for this table.');
}
gs.print('\n--------------------------------------');
gs.print(' SUMMARY for table: ' + targetTable);
gs.print('Total active scripts scanned: ' + totalCount);
gs.print('Originals with duplicates: ' + groupsWithDuplicates);
gs.print('Total duplicates detected: ' + duplicateCount);
gs.print('--------------------------------------');
The script makes no changes to records. It simply lists each duplicate group with key details such as the script name, type, order, creation date, and sys_id, followed by a summary of the total scripts scanned, the originals with duplicates, and the overall duplicates detected
I’m open to ideas and feedback, so feel free to share any suggestions in the comments. If you found this post helpful or even a little musing, please mark it helpful, it keeps the learning going!
Thanks and Regards,
Mohammed Zakir
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
6 hours ago
Hi @Mohammed8
Great Article !!
Below suggestion will optimize your code :
Key Improvements
-
Reduced string concatenations — used array joins for better readability and performance.
-
Single-pass structure — avoids unnecessary variable resets.
-
More readable output — prints duplicates under each original script.
-
Cleaner key creation — uses array joins for safer and faster key construction.
-
Smaller memory footprint — keeps seen compact, storing only what’s needed.
----------
Code: -
var targetTable = 'change_request'; // Example: 'incident', 'change_request', 'wm_order'
var seen = {};
var totalCount = 0;
var duplicateCount = 0;var gr = new GlideRecord('sys_script_client');
gr.addQuery('table', targetTable);
gr.addQuery('active', true);
gr.orderBy('sys_created_on');
gr.query();gs.print('--- Duplicate Client Script Audit for table: ' + targetTable + ' ---');
gs.print('Sorted by creation date (oldest → newest)');
gs.print('');while (gr.next()) {
totalCount++;// Build a unique key based on critical attributes
var keyParts = [gr.name, gr.ui_type, gr.type, gr.order];
if (gr.type == 'onChange') keyParts.push(gr.field);
var key = keyParts.join('_');// Prepare info line
var info = [
'Name: ' + gr.name,
'Type: ' + gr.type,
gr.type == 'onChange' ? 'Field: ' + gr.field : '',
'Order: ' + gr.order,
'Created: ' + gr.sys_created_on.getDisplayValue(),
'Sys_id: ' + gr.sys_id
].filter(Boolean).join(' | ');if (!seen[key]) {
seen[key] = { original: info, duplicates: [] };
} else {
seen[key].duplicates.push(info);
duplicateCount++;
}
}// Output results
var groupsWithDuplicates = 0;
for (var key in seen) {
var group = seen[key];
if (group.duplicates.length > 0) {
groupsWithDuplicates++;
gs.print('\n' + group.original);
gs.print('Duplicate count: ' + group.duplicates.length);
group.duplicates.forEach(function(d) { gs.print(' → ' + d); });
}
}if (groupsWithDuplicates === 0) {
gs.print('\nNo duplicate client scripts found for this table.');
}gs.print('\n--------------------------------------');
gs.print(' SUMMARY for table: ' + targetTable);
gs.print('Total active scripts scanned: ' + totalCount);
gs.print('Groups with duplicates: ' + groupsWithDuplicates);
gs.print('Total duplicates detected: ' + duplicateCount);
gs.print('--------------------------------------');
If you found my response helpful, I would greatly appreciate it if you could mark it as "Accepted Solution" and "Helpful."
Your support not only benefits the community but also encourages me to continue assisting. Thank you so much!
Thanks and Regards
Ravi Gaurav | ServiceNow MVP 2025,2024 | ServiceNow Practice Lead | Solution Architect
CGI
M.Tech in Data Science & AI
YouTube: https://www.youtube.com/@learnservicenowwithravi
LinkedIn: https://www.linkedin.com/in/ravi-gaurav-a67542aa/
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 hours ago
