Skip to content

Commit 7b4a419

Browse files
authored
Merge branch 'ServiceNowDevProgram:main' into main
2 parents 9f771b3 + 07adccc commit 7b4a419

File tree

5 files changed

+134
-0
lines changed
  • Modern Development/Service Portal Widgets/Catalog Item Explorer
  • Server-Side Components/Background Scripts/Merge Duplicate User Records Automatically
  • Specialized Areas/Fix scripts

5 files changed

+134
-0
lines changed

Modern Development/Service Portal Widgets/Catalog Item Explorer/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,8 @@ The primary goal of the Catalog Item Explorer widget is to serve as a valuable l
2424
7. **Quick Search Placeholder:** Define the placeholder message for the Quick Search field to align with your portal's user interface.
2525
8. **Widget Title:** Customize the title of the widget to match its purpose within your Service Portal.
2626
9. **Copyright Display:** Choose whether to display copyright information in the bottom right corner of the widget.
27+
28+
## Latest Update (v1.21):
29+
- **Support for the external URL content items.
30+
- **The default target window changed to "_self" (same window).
31+
- **Option to open an item in the new window added at the end of the row.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Merge Duplicate User Records Automatically
2+
3+
4+
Automatically detects and merges duplicate User records in ServiceNow based on the email address.
5+
6+
Ensures data integrity and prevents duplicate entries.
7+
8+
Reassigns related records (e.g., incidents) to a master record.
9+
10+
Deactivates duplicate users.
11+
12+
In this UseCase
13+
Multiple users exist with the same email address.
14+
15+
The first record found is treated as the master user.
16+
17+
All duplicates are: Reassigned in related records (e.g., tasks, incidents).
18+
19+
Marked inactive.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
(function() {
2+
3+
var userEmailMap = {};
4+
var userCreatedMap = {};
5+
var duplicatesFound = 0;
6+
7+
var userGR = new GlideRecord('sys_user');
8+
userGR.addNotNullQuery('email');
9+
userGR.addQuery('active', true);
10+
userGR.orderBy('email'); // Group by email
11+
userGR.query();
12+
13+
while (userGR.next()) {
14+
var email = userGR.email.toLowerCase();
15+
var createdOn = new GlideDateTime(userGR.sys_created_on).getNumericValue(); // Convert to timestamp
16+
17+
if (!userEmailMap[email]) {
18+
// First user found for this email temporarily mark as master
19+
userEmailMap[email] = userGR.sys_id.toString();
20+
userCreatedMap[email] = createdOn;
21+
} else {
22+
// Another user with same email found
23+
var masterSysId = userEmailMap[email];
24+
var masterCreatedOn = userCreatedMap[email];
25+
26+
var masterIsOlder = createdOn > masterCreatedOn ? true : false;
27+
28+
if (masterIsOlder) {
29+
// If this user was created later, we keep the existing master
30+
// earliest created record will be accepted
31+
mergeDuplicateUser(userGR, masterSysId);
32+
} else {
33+
// If this user was created earlier, this becomes the new master
34+
var oldMasterGR = new GlideRecord('sys_user');
35+
if (oldMasterGR.get(masterSysId)) {
36+
mergeDuplicateUser(oldMasterGR, userGR.sys_id); // merge old master into new master
37+
}
38+
// Update maps
39+
userEmailMap[email] = userGR.sys_id.toString();
40+
userCreatedMap[email] = createdOn;
41+
}
42+
43+
duplicatesFound++;
44+
}
45+
}
46+
47+
gs.info("Total duplicates merged: " + duplicatesFound);
48+
49+
50+
51+
function mergeDuplicateUser(duplicateGR, masterSysId) {
52+
// Reassign related incidents
53+
var incGR = new GlideRecord('incident');
54+
incGR.addQuery('caller_id', duplicateGR.sys_id);
55+
incGR.query();
56+
var count = 0;
57+
while (incGR.next()) {
58+
incGR.caller_id = masterSysId;
59+
incGR.update();
60+
count++;
61+
}
62+
63+
// Deactivate user
64+
duplicateGR.active = false;
65+
duplicateGR.u_merged_to = masterSysId; // optional custom field
66+
duplicateGR.update();
67+
68+
gs.info("Merged duplicate user '" + duplicateGR.name + "' → master: " + masterSysId + ". Reassigned " + count + " incidents.");
69+
}
70+
71+
})();
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
Check if manager of group is inactive.
3+
Replace the manager with oldest group member.
4+
*/
5+
function replacewithActiveManager() {
6+
var inactiveMgrGrp = new GlideRecord('sys_user_group'); // Glide group Table
7+
inactiveMgrGrp.addEncodedQuery('manager.active=false'); // get groups with inactive managers
8+
inactiveMgrGrp.query();
9+
while (inactiveMgrGrp.next()) {
10+
inactiveMgrGrp.setValue('manager', getOlderGroupMember(inactiveMgrGrp).sys_id); // set inactive manager with active group member.
11+
inactiveMgrGrp.autoSysFields(false);
12+
inactiveMgrGrp.update();
13+
gs.info("Group " + inactiveMgrGrp.name + " manager changed to " + getOlderGroupMember(inactiveMgrGrp).name);
14+
}
15+
16+
/*
17+
input: group, type = string.
18+
Function return the older group member user record
19+
*/
20+
function getOlderGroupMember(grp) {
21+
var getUser = new GlideRecord('sys_user_grmember'); // Glide group member table
22+
getUser.addEncodedQuery('user.active=true^group=' + grp.getUniqueValue()); // encoded query to get group member.
23+
getUser.orderByAsc('sys_created_on'); // get oldest added group member
24+
getUser.query();
25+
if (getUser.next())
26+
return getUser.user.getRefRecord();
27+
else
28+
gs.info("Group " + grp.name + " does not have any active user"); // incase there is no active user in group
29+
}
30+
}
31+
replacewithActiveManager(); // main function to replace inactive manager.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
*************
2+
This script will query the group table and look for groups with inactive members. The script will replace the inactive manager with the oldest active member of the group.
3+
4+
Logs: If no active members are there in group //gs.info("Group " + grp.name + " does not have any active user");
5+
6+
After manager is replaced : gs.info("Group " + inactiveMgrGrp.name + " manager changed to " + getOlderGroupMember(inactiveMgrGrp).name);
7+
8+
*************

0 commit comments

Comments
 (0)