Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

Business Rule or similar to update the manager field when a user logs in

wiganmichae
Tera Contributor

Hi,

I have an issue where when a user logs in I want the system to change the manager to a set person if the manager field is either empty or the manager in there is either inactive or locked out.

I have an async business rule set to run after update and run the below script but it doesn't seem to be triggering or working as expected.

 

(function executeRule(current, previous /*null when async*/) {


    var currentUserID = currentUser.getID(); 
    var user = new GlideRecord('sys_user');

    if (user.get(currentUserID)) {
        var managerID = user.manager;
        var manager = new GlideRecord('sys_user');

        // Check if manager is empty
        if (!managerID) {
            jslog('No manager assigned. Changing manager for user: ' + user.user_name);
            user.manager = '7c7b45b31bfa7910bc98eb59b04bcb76'; // Replace with the new manager's sys_id
            user.update();
            return;
        }

        // Check if the current manager is active or not locked out
        if (manager.get(managerID)) {
            if (!manager.active || manager.locked_out) {
                jslog('Manager is inactive or locked out. Changing manager for user: ' + user.user_name);
                user.manager = '7c7b45b31bfa7910bc98eb59b04bcb76'; // Replace with the new manager's sys_id
                user.update();
            }
        }
    }

    function jslog(message) {
        gs.info('Business Rule: Update Manager on Login - ' + message);
    }

})(current, previous);

 

 

Any help to get this working would be greatly appreciated. 

1 ACCEPTED SOLUTION

Sarthak Kashyap
Kilo Sage

Hi @wiganmichae ,

 

I tried your code in my PDI and it is working fine for me please check below code

(function executeRule(current, previous /*null when async*/ ) {

    // Add your code here
    var currentUserID = current.sys_id; // I made changes here
	gs.log("currentUserID = " + currentUserID);
    var user = new GlideRecord('sys_user');

    if (user.get(currentUserID)) {
        var managerID = user.manager;
		gs.log("Manager çheck = " + managerID);
        var manager = new GlideRecord('sys_user');

        // Check if manager is emptyi
        if (!managerID) {
            gs.log('No manager assigned. Changing manager for user: ' + user.user_name);
            user.manager = '4ddc2f1193576a109305f520ed03d681'; // Replace with the new manager's sys_id
			user.update()
        }

        // Check if the current manager is active or not locked out
        if (manager.get(managerID)) {
            if (!manager.active || manager.locked_out) {
                gs.log('Manager is inactive or locked out. Changing manager for user: ' + user.user_name);
                user.manager = '4ddc2f1193576a109305f520ed03d681'; // Replace with the new manager's sys_id
				user.update()
            }
        }
    }

})(current, previous);

 

Result

SarthakKashyap_0-1761296027338.png

 

Please mark my answer correct and helpful if this works for you

Thanks and Regards,

Sarthak

View solution in original post

7 REPLIES 7

MaxMixali
Tera Guru

ServiceNow – Set/Correct a User’s Manager at Login (without recursion)

Why your current approach fails
- An AFTER UPDATE Business Rule on sys_user will NOT run on login (logging in does not update sys_user).
- The code uses currentUser.getID() (undefined). Use gs.getUserID().
- Calling user.update() from arbitrary contexts can retrigger BRs; prefer a login-triggered context and a silent update.

Two supported patterns
======================

Pattern A — Script Action on 'user.login' (recommended)
------------------------------------------------------
1) Go to: System Policy > Script Actions → New
2) Set:
- Active: true
- When to run: After
- Event name: user.login (built-in event fired on successful login)
3) Script (replace MANAGER_SYSID with your manager user sys_id):

(function() {
var MANAGER_SYSID = '7c7b45b31bfa7910bc98eb59b04bcb76';

var uid = gs.getUserID();
if (!uid) return;

// Do not run for special users if desired
// if (gs.hasRole('admin')) return; // optional

var u = new GlideRecord('sys_user');
if (!u.get(uid)) return;

var needsChange = false;

// If manager is empty
if (!u.getValue('manager')) {
needsChange = true;
} else {
// Load manager and validate
var mgr = u.getElement('manager').getRefRecord();
if (!mgr || mgr.active == false || mgr.locked_out == true) {
needsChange = true;
}
}

if (needsChange) {
u.setWorkflow(false); // avoid BR/Flow/Notifications
u.setUseEngines(false);
u.setValue('manager', MANAGER_SYSID);
u.update();
}
})();

Notes:
- Runs ONLY when a user logs in (no need to watch table updates).
- setWorkflow(false)/setUseEngines(false) prevents side effects.

Pattern B — Business Rule on sys_user_session (after insert)
------------------------------------------------------------
1) Table: sys_user_session
2) When: After Insert (a row is created at login)
3) Condition: current.user IS NOT EMPTY
4) Script:

(function executeRule(current, previous /*null when async*/) {
var MANAGER_SYSID = '7c7b45b31bfa7910bc98eb59b04bcb76';
var uid = current.user.toString();
if (!uid) return;

var u = new GlideRecord('sys_user');
if (!u.get(uid)) return;

var needsChange = false;

if (!u.getValue('manager')) {
needsChange = true;
} else {
var mgr = u.getElement('manager').getRefRecord();
if (!mgr || mgr.active == false || mgr.locked_out == true) {
needsChange = true;
}
}

if (needsChange) {
u.setWorkflow(false);
u.setUseEngines(false);
u.setValue('manager', MANAGER_SYSID);
u.update();
}
})(current, previous);

Troubleshooting & tips
----------------------
- Ensure the MANAGER_SYSID points to an ACTIVE, not locked_out user.
- Avoid recursion: never place this on an UPDATE rule against sys_user.
- Logging: use gs.info(...) in the script action while testing.
- Security: confirm the account running the script has rights to update sys_user.manager.
- If you must run conditionally (e.g., only for certain companies), add checks before update.

TL;DR
-----
Don’t use an AFTER UPDATE Business Rule on sys_user for login logic. Use a **Script Action on user.login** (or BR on sys_user_session AFTER INSERT), then do a **silent update** of the manager when empty/inactive/locked_out.

MaxMixali
Tera Guru

ServiceNow – Update a User’s Manager on Login (Working Patterns & Fixes)

Your current approach (async BR, using currentUser) won’t trigger on login and has a few issues:
- A Business Rule won’t run “on login” unless a field on sys_user actually changes. (Login does update last_login / last_login_time.)
- In a BR script you cannot use currentUser; use gs.getUserID().
- You’re re-querying the same user; use current (if the BR is on sys_user) or a clean GlideRecord with guards.
- Prevent recursion when you update sys_user from a sys_user BR.

Below are two reliable patterns. Prefer Pattern A.

------------------------------------------------------------
Pattern A (Recommended): Script Action on Login Event
------------------------------------------------------------
• Runs when the platform fires the 'user.login' event.
• No need to rely on sys_user field changes.

1) Create Script Action
- Navigate: System Policy → Events → Registry → ensure event 'user.login' exists (it is OOB).
- Go to: System Policy → Events → Script Actions → New
• Name: Set Manager on Login
• Event name: user.login
• Active: true
• Order: 100

2) Script (Script Action)
(function() {
var TARGET_MANAGER = '7c7b45b31bfa7910bc98eb59b04bcb76'; // TODO: replace

// The user who just logged in is passed in parm1 (OOB)
var uid = event.parm1 || gs.getUserID();
if (!uid) return;

var usr = new GlideRecord('sys_user');
if (!usr.get(uid)) return;

function setManager(gr, mgrSysId) {
// safety: avoid loops and system updates
gr.setValue('manager', mgrSysId);
gr.setWorkflow(false);
gr.autoSysFields(false);
gr.update();
}

var mgrId = usr.getValue('manager');
if (!mgrId) {
gs.info('Login manager fix: assigning default manager to ' + usr.getValue('user_name'));
setManager(usr, TARGET_MANAGER);
return;
}

var mgr = new GlideRecord('sys_user');
if (!mgr.get(mgrId)) {
gs.info('Login manager fix: existing manager missing, assigning default manager to ' + usr.getValue('user_name'));
setManager(usr, TARGET_MANAGER);
return;
}

var inactive = (mgr.getValue('active') == 'false');
var locked = (mgr.getValue('locked_out') == 'true');

if (inactive || locked) {
gs.info('Login manager fix: manager inactive/locked, assigning default manager to ' + usr.getValue('user_name'));
setManager(usr, TARGET_MANAGER);
}
})();

Notes
- event.parm1 is the sys_id of the user who logged in (OOB behavior).
- Keep this Script Action lightweight to avoid login latency.

------------------------------------------------------------
Pattern B: Business Rule on sys_user (last_login change)
------------------------------------------------------------
• Runs when sys_user.last_login_time (or last_login) changes at login.

1) Create Business Rule
- Table: sys_user
- When: after update (can be async = true)
- Condition: current.last_login_time.changes() || current.last_login.changes()
- Advanced: ✓

2) Script (Business Rule)
(function executeRule(current, previous) {
var TARGET_MANAGER = '7c7b45b31bfa7910bc98eb59b04bcb76'; // TODO: replace

// guard: don't run if already set to target
if (current.getValue('manager') == TARGET_MANAGER)
return;

var mgrId = current.getValue('manager');

// helper to update safely without re-triggering the rule
function updateManager(gr, mgrSysId) {
var u = new GlideRecord('sys_user');
if (!u.get(gr.getUniqueValue())) return;
u.setValue('manager', mgrSysId);
u.setWorkflow(false);
u.autoSysFields(false);
u.update();
}

if (!mgrId) {
gs.info('Login manager BR: assigning default manager to ' + current.getValue('user_name'));
updateManager(current, TARGET_MANAGER);
return;
}

var mgr = new GlideRecord('sys_user');
if (!mgr.get(mgrId)) {
gs.info('Login manager BR: manager ref broken, assigning default manager to ' + current.getValue('user_name'));
updateManager(current, TARGET_MANAGER);
return;
}

var inactive = (mgr.getValue('active') == 'false');
var locked = (mgr.getValue('locked_out') == 'true');

if (inactive || locked) {
gs.info('Login manager BR: manager inactive/locked, assigning default manager to ' + current.getValue('user_name'));
updateManager(current, TARGET_MANAGER);
}
})(current, previous);

Notes
- Use changes() on last_login_time or last_login so the rule only runs on login updates.
- Use a second GlideRecord with setWorkflow(false) to avoid recursive triggers.
- Don’t use currentUser.getID(); use gs.getUserID() when needed.

------------------------------------------------------------
Debugging checklist
------------------------------------------------------------
- Confirm 'user.login' events are firing (System Logs → Events → filter by name = user.login).
- If using BR: verify that last_login_time changes on login in your instance version.
- Ensure the target manager sys_id is valid and user is active/unlocked.
- Add temporary gs.info() logs to verify paths.
- Test with a non-admin user; admins may have atypical profiles (e.g., no company, impersonation behavior).

------------------------------------------------------------
Security & Governance
------------------------------------------------------------
- Document why you’re defaulting managers; consider excluding privileged accounts (admin, security_admin).
- Wrap behind a system property (e.g., glide.company.default_manager) to avoid hardcoding.
- Consider a one-time data correction job if many users lack a manager today, then keep this logic for future logins only.

 

Sarthak Kashyap
Kilo Sage

Hi @wiganmichae ,

 

I tried your code in my PDI and it is working fine for me please check below code

(function executeRule(current, previous /*null when async*/ ) {

    // Add your code here
    var currentUserID = current.sys_id; // I made changes here
	gs.log("currentUserID = " + currentUserID);
    var user = new GlideRecord('sys_user');

    if (user.get(currentUserID)) {
        var managerID = user.manager;
		gs.log("Manager çheck = " + managerID);
        var manager = new GlideRecord('sys_user');

        // Check if manager is emptyi
        if (!managerID) {
            gs.log('No manager assigned. Changing manager for user: ' + user.user_name);
            user.manager = '4ddc2f1193576a109305f520ed03d681'; // Replace with the new manager's sys_id
			user.update()
        }

        // Check if the current manager is active or not locked out
        if (manager.get(managerID)) {
            if (!manager.active || manager.locked_out) {
                gs.log('Manager is inactive or locked out. Changing manager for user: ' + user.user_name);
                user.manager = '4ddc2f1193576a109305f520ed03d681'; // Replace with the new manager's sys_id
				user.update()
            }
        }
    }

})(current, previous);

 

Result

SarthakKashyap_0-1761296027338.png

 

Please mark my answer correct and helpful if this works for you

Thanks and Regards,

Sarthak

I did this thing on Before BR

 

Please mark my answer correct and helpful if this works for you

Thanks and Regards,

Sarthak