From 80b7f89b0ac7a5c932ed4af3c24c3801977ff20b Mon Sep 17 00:00:00 2001 From: keshava-palisetti Date: Mon, 27 Oct 2025 18:49:41 +0530 Subject: [PATCH 1/2] Create Readme.md Auto deactivate inactive users while informing their manager --- .../Readme.md | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Server-Side Components/Scheduled Jobs/Auto deactivate the inactive users/Readme.md diff --git a/Server-Side Components/Scheduled Jobs/Auto deactivate the inactive users/Readme.md b/Server-Side Components/Scheduled Jobs/Auto deactivate the inactive users/Readme.md new file mode 100644 index 0000000000..1953c11f9e --- /dev/null +++ b/Server-Side Components/Scheduled Jobs/Auto deactivate the inactive users/Readme.md @@ -0,0 +1,43 @@ +Purpose + This scheduled job automatically identifies inactive users in the ServiceNow instance and deactivates their accounts if they have not logged in for a specified period (default: 3 months). +It ensures compliance, reduces clutter, and maintains security by removing stale user accounts. + +Key Features + Runs automatically once per month. + Identifies users who have been inactive for a defined number of months. + Supports dry-run testing to safely validate before applying changes. + Deactivates inactive users automatically. + Sends email notifications to both users and their managers upon deactivation. + Logs all activities in the system log for auditing purposes. + +Script Workflow + +1. Calculate Cutoff Date +The script calculates a cutoff date by subtracting the configured number of months (default: 3) from the current date. +Any user created before this date and who has not logged in since is considered inactive. + +2. Query Eligible Users +The script searches the sys_user table for records meeting these conditions: +active = true +sys_created_on <= cutoffDate +last_login_time <= cutoffDate + +3. Process Each User +For every matching user, the script: +Logs user details (name, email, last login, manager). +Deactivates the account (if DRY_RUN is false). +Sends notification emails. + +4. Send Notification to User +Sends a plain-text email to the user informing them that their account was deactivated due to inactivity. +Includes instructions on how to request reactivation. + +5. Send Notification to Manager +If the user has a manager assigned, an additional email is sent to the manager. +The email contains the user’s details and the date of last login for awareness. + +6. Log Summary +At the end of execution, the script logs: +Total users found +Total users deactivated +Status of the run (Dry Run or Actual) From 0e2dc1ef1b0e6ab6c9328c1a779ebf712d51eb7c Mon Sep 17 00:00:00 2001 From: keshava-palisetti Date: Mon, 27 Oct 2025 18:53:50 +0530 Subject: [PATCH 2/2] Scheduled job ServiceNow code snippet Auto deactivate inactive users --- .../auto_cleanup_inactive_users.js | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 Server-Side Components/Scheduled Jobs/Auto deactivate the inactive users/auto_cleanup_inactive_users.js diff --git a/Server-Side Components/Scheduled Jobs/Auto deactivate the inactive users/auto_cleanup_inactive_users.js b/Server-Side Components/Scheduled Jobs/Auto deactivate the inactive users/auto_cleanup_inactive_users.js new file mode 100644 index 0000000000..580528419b --- /dev/null +++ b/Server-Side Components/Scheduled Jobs/Auto deactivate the inactive users/auto_cleanup_inactive_users.js @@ -0,0 +1,95 @@ +(function executeAutoUserCleanup() { + + /*************************************************************** + * AUTO CLEANUP INACTIVE USERS - MONTHLY JOB + * ------------------------------------------------------------ + * This script automatically deactivates users who have not + * logged in for a defined number of months. It can also send + * notifications to both the user and their manager. + * + * SAFETY: Use DRY_RUN = true first to test (no updates). + ***************************************************************/ + + // === CONFIGURATION === + var MONTHS_THRESHOLD = 3; // Inactive period threshold (in months) + var DRY_RUN = true; // true = test mode, no database updates + var BATCH_LIMIT = 1000; // Max records per execution + var FROM_EMAIL = 'no-reply@yourcompany.com'; // sender email address + + // === STEP 1: Calculate cutoff date === + var cutoffDate = new GlideDateTime(); + cutoffDate.addMonths(-MONTHS_THRESHOLD); + + gs.info('[UserCleanup] Job started. Cutoff date: ' + cutoffDate.getDisplayValue() + + ' | DRY_RUN: ' + DRY_RUN + ' | Threshold: ' + MONTHS_THRESHOLD + ' months'); + + // === STEP 2: Query eligible users === + var userGr = new GlideRecord('sys_user'); + userGr.addQuery('active', true); // only active users + userGr.addQuery('sys_created_on', '<=', cutoffDate); // created before cutoff + userGr.addQuery('last_login_time', '<=', cutoffDate); // no recent login + userGr.setLimit(BATCH_LIMIT); // safety limit + userGr.query(); + + var totalFound = 0; + var totalDeactivated = 0; + + // === STEP 3: Loop through each user === + while (userGr.next()) { + totalFound++; + + var userName = userGr.name.toString(); + var userEmail = userGr.email.toString(); + var lastLogin = userGr.last_login_time ? userGr.last_login_time.getDisplayValue() : 'Never'; + var managerEmail = (userGr.manager && userGr.manager.email) ? userGr.manager.email.toString() : null; + + gs.info('[UserCleanup] Found user: ' + userName + + ' | Email: ' + userEmail + + ' | Last Login: ' + lastLogin + + ' | Manager: ' + (managerEmail || 'None')); + + if (!DRY_RUN) { + + // === STEP 4: Deactivate the user === + userGr.active = false; + userGr.update(); + totalDeactivated++; + + // === STEP 5: Send notification to user === + if (userEmail) { + var subjectUser = 'Your ServiceNow account has been deactivated due to inactivity'; + var bodyUser = + 'Hello ' + userName + ',\n\n' + + 'Your ServiceNow account has been automatically deactivated because there has been no login activity ' + + 'for over ' + MONTHS_THRESHOLD + ' months.\n\n' + + 'If you believe this is a mistake or require access, please contact the IT Service Desk.\n\n' + + 'Regards,\nIT Service Management Team'; + + gs.email(FROM_EMAIL, userEmail, subjectUser, bodyUser); + gs.info('[UserCleanup] Email sent to user: ' + userEmail); + } + + // === STEP 6: Send notification to manager === + if (managerEmail) { + var subjectMgr = 'User under your management has been deactivated'; + var bodyMgr = + 'Hello,\n\n' + + 'The following user under your management has been deactivated due to inactivity:\n\n' + + 'User: ' + userName + '\n' + + 'Last Login: ' + lastLogin + '\n\n' + + 'If this account is still required, please raise a ServiceNow access request.\n\n' + + 'Regards,\nIT Service Management Team'; + + gs.email(FROM_EMAIL, managerEmail, subjectMgr, bodyMgr); + gs.info('[UserCleanup] Email sent to manager: ' + managerEmail); + } + } + } + + // === STEP 7: Log summary === + gs.info('[UserCleanup] Total users found: ' + totalFound); + gs.info('[UserCleanup] Total users deactivated: ' + totalDeactivated + + (DRY_RUN ? ' (Dry Run - no records updated)' : '')); + +})(); +