From 21b615f12031c3d78653b5c67b681cf9a69c3799 Mon Sep 17 00:00:00 2001 From: ReddySurendra <130588276+Suri123789@users.noreply.github.com> Date: Tue, 27 May 2025 12:30:58 +0530 Subject: [PATCH 1/4] Code for Moveworks bot messages for Flow to include url links --- Moveworks messages html for Flow | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Moveworks messages html for Flow diff --git a/Moveworks messages html for Flow b/Moveworks messages html for Flow new file mode 100644 index 0000000000..c228104146 --- /dev/null +++ b/Moveworks messages html for Flow @@ -0,0 +1,38 @@ +var article = fd_data._1__look_up_record.record; + +// Safely retrieve fields with null checks for a KB Article +var sys_id = article.sys_id || ''; +var articleTitle = article.short_description || 'N/A'; +var requestedBy = fd_data.trigger.current.sys_created_by; +var articleNumber = article.number || 'N/A'; +var requestedOn = article.sys_created_on || 'N/A'; +var kbName = (article.kb_knowledge_base && article.kb_knowledge_base.title) || 'N/A'; +var knowledgeManagers = (article.kb_knowledge_base && article.kb_knowledge_base.owner && article.kb_knowledge_base.owner.getDisplayValue()) || 'N/A'; + +// Base URL +var baseUrl = gs.getProperty('glide.servlet.uri') || ''; +var kbLink = baseUrl + 'kb_knowledge.do?sys_id=' + sys_id; +//Below are links for opening the record in servicenow +var approveLink = baseUrl + 'sysapproval_approver.do?action=approve&sys_id=' + sys_id; +var rejectLink = baseUrl + 'sysapproval_approver.do?action=reject&sys_id=' + sys_id; +//Below lines are for email template which is used to create email inbound template. +var inst ='inspirebrandsdev'; +var approveSub = 'RE: '+ articleNumber +' Approve KB Article '; +var body = 'Please do not change the subject, just click send message.'; +var rejectSub = 'RE: '+ articleNumber +' Reject KB Article '; + + +// HTML message +var message = + 'Pending approval request from ServiceNow

' + + '' + articleNumber + ': ' + articleTitle + '

' + + 'Requested by: ' + requestedBy + '
' + + 'Requested on: ' + requestedOn + '
' + + 'Knowledge Base: ' + kbName + '
' + + 'Knowledge Managers: ' + knowledgeManagers + '

' + + 'Approve link : Click here
'+ + 'Reject link : Click here
'; + //'Approve link : Click here to approve
' + + //'Reject link: Click here to reject'; + +return message; From 94f7b15b9606b44ed6875e5e1945789e9de6534c Mon Sep 17 00:00:00 2001 From: ReddySurendra <130588276+Suri123789@users.noreply.github.com> Date: Tue, 28 Oct 2025 18:42:51 +0530 Subject: [PATCH 2/4] Create script.js --- .../Clean up Inactive User access/script.js | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Server-Side Components/Scheduled Jobs/Clean up Inactive User access/script.js diff --git a/Server-Side Components/Scheduled Jobs/Clean up Inactive User access/script.js b/Server-Side Components/Scheduled Jobs/Clean up Inactive User access/script.js new file mode 100644 index 0000000000..5f2f426dfd --- /dev/null +++ b/Server-Side Components/Scheduled Jobs/Clean up Inactive User access/script.js @@ -0,0 +1,59 @@ +///This is a Scheduled Job Script to be added in "Run this script" +//replace the email in line 56- 'email.setFrom('xyz@service-now.com');' +//replace the property name in line 44 'var recipientList = gs.getProperty('glide.xyz.admin.email.recipients');' + +var emailBody = 'Daily Inactive User Group/Role/Task Clean-up Completed: \n

'; + +//REMOVE INACTIVE USERS FROM GROUPS +var queryString = "user.active=false^user.web_service_access_only=false^user.sourceSTARTSWITHldap:"; //query to find inactive members belonging to groups and ignores any users with "web service access only" = TRUE. +var recGrp = new GlideRecord('sys_user_grmember'); //searches the User Group Member table +recGrp.addEncodedQuery(queryString); +recGrp.query(); +while (recGrp.next()) { + emailBody += 'Inactive User, ' + recGrp.user.getDisplayValue() + ', member of Group: ' + recGrp.group.getDisplayValue() + ' was removed from Group.\n
'; + gs.log('Inactive User, ' + recGrp.user.getDisplayValue() + ', member of Group: ' + recGrp.group.getDisplayValue() + ' was removed from Group.'); + recGrp.deleteRecord(); //deletes group membership record from inactive user +} + +//REMOVE ROLES FROM INACTIVE USERS THAT WERE NOT ADDED BY GROUP MEMBERSHIP +var recRole = new GlideRecord('sys_user_has_role'); // search view User Has Role table +var queryString2 = "user.active=false^user.web_service_access_only=false^user.sourceSTARTSWITHldap:^inherited=false"; +recRole.addEncodedQuery(queryString2); // find inactive users that have a role assigned and ignores any users with "web service access only" = TRUE. +recRole.query(); +while (recRole.next()) { + emailBody += 'Inactive User, ' + recRole.user.name + ' found - Role: ' + recRole.role.getDisplayValue() + ', was removed.\n
'; + gs.log('Inactive User, ' + recRole.user.name + ' found - Role: ' + recRole.role.getDisplayValue() + ', was removed.'); // add info message to system log about what user was inactive and role was removed + recRole.deleteRecord(); //deletes role record from inactive user +} + +//CLEARS ASSIGNED TO ON ACTIVE TASKS ASSIGNED TO INACTIVE USERS +var recTask = new GlideRecord('task'); // search task table +var queryString3 = "assigned_to.active=false^assigned_to.web_service_access_only=false^active=true"; +recTask.addEncodedQuery(queryString3); // find inactive users that have active tasks assigned to them and ignores any users with "web service access only" = TRUE. +recTask.query(); +while (recTask.next()) { + emailBody += 'Removed task from Inactive User: ' + recTask.assigned_to.getDisplayValue() + ' ' + recTask.number + '.\n
'; + gs.log('Removed task from Inactive User: ' + recTask.assigned_to.getDisplayValue() + ' ' + recTask.number); // add message about what user was inactive tasks removed + recTask.work_notes = 'System Administrator removed "Assigned to" value as the user is no longer active.'; //add work note explanation without workflow + recTask.update(); + recTask.assigned_to = ''; + recTask.setWorkflow(false); //removes assigned_to value without workflow + recTask.update(); +} + +var recipientList = gs.getProperty('glide.xyz.admin.email.recipients'); +var email = new GlideEmailOutbound(); +email.setSubject('Daily Inactive User Group/Role/Task Clean-up Completed'); +email.setBody(emailBody); +if (recipientList.includes(',')) { + var recipients = recipientList.split(","); + for (var i = 0; i < recipients.length; i++) { + email.addRecipient(recipients[i]); // Add recipients from system property + } +} else { + email.addRecipient(recipientList); // Add single recipient from system property +} +email.setFrom('xyz@service-now.com'); +email.save(); + +gs.log('Daily Inactive User Group/Role/Task Clean-up Completed: \n\n' + emailBody); From 117c02695733883ef876481f2ed346fb5b34b29e Mon Sep 17 00:00:00 2001 From: ReddySurendra <130588276+Suri123789@users.noreply.github.com> Date: Tue, 28 Oct 2025 18:47:25 +0530 Subject: [PATCH 3/4] Create readme.md --- .../Clean up Inactive User access/readme.md | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 Server-Side Components/Scheduled Jobs/Clean up Inactive User access/readme.md diff --git a/Server-Side Components/Scheduled Jobs/Clean up Inactive User access/readme.md b/Server-Side Components/Scheduled Jobs/Clean up Inactive User access/readme.md new file mode 100644 index 0000000000..efd3f7fa29 --- /dev/null +++ b/Server-Side Components/Scheduled Jobs/Clean up Inactive User access/readme.md @@ -0,0 +1,82 @@ +๐Ÿงน Inactive User Cleanup โ€” ServiceNow Scheduled Job +๐Ÿ“Œ Overview + +This script automates daily cleanup of access and assignments for inactive users in ServiceNow. +It removes orphaned access, ensures task accountability, and sends an email summary upon completion. + +โœ… Features Included +๐Ÿ”น Inactive Group Membership Cleanup + +Searches User Group Member table (sys_user_grmember) +Identifies inactive users (excluding Web Service Access Only accounts) +Removes them from all associated groups +Logs each removal in system logs +Adds removal details to the summary email + +๐Ÿ”น Direct Role Revocation + +Searches User Has Role table (sys_user_has_role) +Removes roles not inherited via group membership +Prevents unauthorized access after deactivation +Logs each role removed +Included in daily summary email + +๐Ÿ”น Task Ownership Cleanup + +Searches Task table (task) +Finds active tasks assigned to inactive users +Clears the Assigned To field without triggering workflow +Adds work notes for audit traceability +Logs entries + email reporting +All actions skip users where: web_service_access_only = true + +๐Ÿ›  Script Placement & Configuration +Field Value +Script Type โœ… Scheduled Script Execution +Location Run this script section + +Before using in your instance, update the following in script: + +Line Update Required +Line 56 Replace sender email in email.setFrom('xyz@service-now.com'); +Line 44 Replace system property name in gs.getProperty('glide.xyz.admin.email.recipients'); +๐Ÿ” System Property Required + +Create or update the System Property to store email recipients: + +Name (example) Value (example) +glide.xyz.admin.email.recipients admin@example.com,user@example.com + +Supports single or comma-separated recipients โœ… + +โœ‰๏ธ Email Summary Includes + +Users removed from groups +Direct roles removed +Active tasks unassigned +Timestamped logs for auditing + +๐Ÿ“ Work Notes Added + +For tasks reassigned: +System Administrator removed "Assigned to" value as the user is no longer active. + +โš ๏ธ Best Practices + +Run in sub-prod first +Ensure proper backups/audit compliance +Schedule at low-traffic hours +Monitor logs initially for data impact + +๐Ÿงฉ Extendability Ideas + +You can easily modify: +Email template (HTML formatting) +Query filters for additional cleanup criteria +Logging to include sys_id values +Scheduling frequency (default recommended: Daily) + +๐Ÿง‘โ€๐Ÿ’ป Maintainers + +Feel free to update script name, System Property naming, and sender email for your organization. +Pull requests & suggestions welcome! ๐Ÿ™Œ From d66db38bafc3a94ae80792488ab5bc5055ced557 Mon Sep 17 00:00:00 2001 From: ReddySurendra <130588276+Suri123789@users.noreply.github.com> Date: Tue, 28 Oct 2025 19:01:17 +0530 Subject: [PATCH 4/4] Delete Moveworks messages html for Flow --- Moveworks messages html for Flow | 38 -------------------------------- 1 file changed, 38 deletions(-) delete mode 100644 Moveworks messages html for Flow diff --git a/Moveworks messages html for Flow b/Moveworks messages html for Flow deleted file mode 100644 index c228104146..0000000000 --- a/Moveworks messages html for Flow +++ /dev/null @@ -1,38 +0,0 @@ -var article = fd_data._1__look_up_record.record; - -// Safely retrieve fields with null checks for a KB Article -var sys_id = article.sys_id || ''; -var articleTitle = article.short_description || 'N/A'; -var requestedBy = fd_data.trigger.current.sys_created_by; -var articleNumber = article.number || 'N/A'; -var requestedOn = article.sys_created_on || 'N/A'; -var kbName = (article.kb_knowledge_base && article.kb_knowledge_base.title) || 'N/A'; -var knowledgeManagers = (article.kb_knowledge_base && article.kb_knowledge_base.owner && article.kb_knowledge_base.owner.getDisplayValue()) || 'N/A'; - -// Base URL -var baseUrl = gs.getProperty('glide.servlet.uri') || ''; -var kbLink = baseUrl + 'kb_knowledge.do?sys_id=' + sys_id; -//Below are links for opening the record in servicenow -var approveLink = baseUrl + 'sysapproval_approver.do?action=approve&sys_id=' + sys_id; -var rejectLink = baseUrl + 'sysapproval_approver.do?action=reject&sys_id=' + sys_id; -//Below lines are for email template which is used to create email inbound template. -var inst ='inspirebrandsdev'; -var approveSub = 'RE: '+ articleNumber +' Approve KB Article '; -var body = 'Please do not change the subject, just click send message.'; -var rejectSub = 'RE: '+ articleNumber +' Reject KB Article '; - - -// HTML message -var message = - 'Pending approval request from ServiceNow

' + - '' + articleNumber + ': ' + articleTitle + '

' + - 'Requested by: ' + requestedBy + '
' + - 'Requested on: ' + requestedOn + '
' + - 'Knowledge Base: ' + kbName + '
' + - 'Knowledge Managers: ' + knowledgeManagers + '

' + - 'Approve link : Click here
'+ - 'Reject link : Click here
'; - //'Approve link : Click here to approve
' + - //'Reject link: Click here to reject'; - -return message;