- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-28-2023 10:02 AM
Hello everyone, I'm running into an issue with a script I've whipped up and was needing some help. We are trying to automate a system that will take duplicate users, check which user has less incidents/tasks, trigger a workflow to move those incidents/tasks, then archive the old user, and refresh the ldap twice to pull in the users new data from AD.
The issue I'm running into here is, I want to trigger this workflow for every user that needs it ran on at once, however it seems to run one workflow per user pair at a time, this workflow can take 5 minutes to complete and we've got thousands of users that will need to be hit. Any ideas on how I can get this workflow to trigger on all users that need it then wait and check to see if those workflows completed then move on like I have wrote in the script below? I've cut out most of the functions, as the workflow functions are the only ones we are interested in but you can see the step to step process in the main function.
function triggerWorkflow(fromUser, toUser) {
var workflowSysID = '8ecc9eb6db2f49d8498f7914b9961969'; // Provided sys_id for the workflow
var workflow = new Workflow();
var context = workflow.startFlow(workflowSysID, null, 'update', {
from_user: fromUser.sys_id,
to_user: toUser.sys_id
});
gs.info('Workflow triggered to migrate tasks and approvals from ' + fromUser.user_name + ' to ' + toUser.user_name);
return {context: context, pair: {user1: fromUser, user2: toUser, preferredUser: toUser}};
}
function waitForAllWorkflows(workflowContexts) {
var maxAttempts = 10; // Max wait time 15 minutes
var attempts = 0;
while (attempts < maxAttempts) {
var allComplete = true;
workflowContexts.forEach(function(contextInfo) {
var contextGR = new GlideRecord('wf_context');
if (contextGR.get(contextInfo.context) && contextGR.state != 'finished') {
allComplete = false;
}
});
if (allComplete) {
gs.info('All workflows finished for migrating tasks and approvals');
break;
}
attempts++;
gs.sleep(90000); // Sleep for 90 seconds
}
if (!allComplete) {
gs.error('Not all workflows completed within ' + maxAttempts + ' attempts');
}
}
// Main script
function main() {
gs.info('Starting AD migration script');
var duplicates = findDuplicateUsers();
var workflowContexts = [];
var toUsers = [];
var fromUsers = [];
// First, compare tasks and roles for each pair to determine which user to keep
duplicates.forEach(function(pair) {
var preferredUser = compareTasksAndRoles(pair.user1, pair.user2);
if (preferredUser) {
var fromUser = (preferredUser.sys_id === pair.user1.sys_id) ? pair.user2 : pair.user1;
var toUser = preferredUser;
// Queue up the workflow for each user pair
var context = triggerWorkflow(fromUser, toUser);
workflowContexts.push(context);
// Collect toUser and fromUser for LDAP load
if (toUser.ldap_server == 'FID') {
toUsers.push(toUser);
fromUsers.push(fromUser);
}
} else {
gs.info('No preferred user determined for pair: ' + pair.user1.user_name + ' and ' + pair.user2.user_name);
}
});
// Wait for all queued workflows to complete
waitForAllWorkflows(workflowContexts);
// LDAP load for all toUsers
toUsers.forEach(function(user) {
ldapLoadForUser(user);
});
// Wait for 60 seconds before loading fromUsers
gs.sleep(60000);
// LDAP load for all fromUsers
fromUsers.forEach(function(user) {
ldapLoadForUser(user);
});
// Proceed with archiving users
fromUsers.forEach(function(user) {
archiveUser(user);
});
gs.info('AD migration script completed');
}
// Run the main script
main();
Solved! Go to Solution.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-29-2023 09:40 AM
If you want to run it faster, I would put the scripts inside the foreach loop in a script action.
Create an event and then call script action using that event from your script include. That way the calls become asynchronously and wont wait for one job to finish.
Please mark this response as correct or helpful if it assisted you with your question.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-29-2023 09:46 AM
@SanjivMeher Oh that's a pretty good idea, this in particular is a fix script. So would it be better to potentially make a script include that calls that workflow? Then in my fix script have it call that script include? So essentially it'll call the script include multiple times while passing the parameters over?

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-29-2023 09:56 AM
So if this is a fix script, you can make a call to script action from the fix script by triggering an event.
You can google how to use script action, if you haven't used it yet. Script action is different from script include. Below link should help you.
https://servicenowspectaculars.com/what-is-servicenow-script-action/
Please mark this response as correct or helpful if it assisted you with your question.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-29-2023 10:50 AM
I will be testing this by tomorrow, I won't forget to accept your solution if it works tomorrow 🙂 Thank you for your help so far! Greatly appreciated!