← Script library

Background Scripts

Report Duplicate Active User Login Names

Find login names shared by multiple active user records for identity-data review, without changing accounts.

JavaScript
(function reportDuplicateLogins() {
  var prefix = '[SN-Tricks:DuplicateLogins]';
  try {
    var users = new GlideAggregate('sys_user');
    users.addQuery('active', true);
    users.addNotNullQuery('user_name');
    users.addAggregate('COUNT');
    users.groupBy('user_name');
    users.addHaving('COUNT', '>', '1');
    users.query();

    var groups = 0;
    var accounts = 0;
    while (users.next()) {
      var count = parseInt(users.getAggregate('COUNT'), 10);
      var login = String(users.getValue('user_name')).replace(/[\r\n\t]/g, ' ');
      gs.info(prefix + ' login=' + login + ' | active_accounts=' + count);
      groups++;
      accounts += count;
    }
    gs.info(prefix + ' Duplicate login groups=' + groups +
      '; active accounts in those groups=' + accounts + '. No records changed.');
  } catch (error) {
    gs.error(prefix + ' Report failed; disregard partial output: ' + error);
  }
})();

How to use it

1. As an authorized administrator, run in Global scope under System Definition > Scripts - Background in a non-production instance first. This custom diagnostic uses the OOB sys_user table and GlideAggregate; no cross-scope access is required in Global. 2. It filters active=true and populated user_name, groups by user_name, and returns only groups with COUNT greater than one. The summary counts duplicate groups and all active accounts in those groups, not the number of surplus accounts. No matches produces two zero counts. 3. In sub-production, use synthetic records with two active users sharing one login, one unique active login, an inactive user sharing the duplicate login, and empty login values. Expect only the two active duplicates. If uniqueness controls prevent duplicate test data, do not disable them; use mocks and validate the no-match path on the instance. 4. Compare with a sys_user list filtered to Active is true and User ID is not empty, grouped by User ID, in the same domain context. Database collation determines case equivalence; this script does not trim, lowercase, normalize Unicode, or detect similar-looking login names. Empty values are excluded, but whitespace-only values may qualify. 5. Results do not prove an authentication vulnerability or that accounts should be merged or disabled. Identity providers, domain separation, and instance-specific login rules require separate review. Never remediate accounts solely from this report. 6. Logs include login names, which may be email addresses or other personal data. Restrict log access and follow your retention policy. CR, LF, and tab characters are replaced with spaces only for log output; source data is untouched. This administrative aggregate is not an ACL-filtered end-user report. Query business rules and domain visibility can affect results. 7. Aggregation and output are not capped; assess runtime and duplicate-group volume with representative data before production execution. On any exception disregard partial output. The script performs no inserts, updates, deletes, account merges, or notifications, so no data rollback is needed. Ad hoc execution creates no reusable update-set record. Local mock tests are not ServiceNow instance validation.

Adapt the table names, fields, and conditions to your instance. Test the behavior in a development environment before using it in production.