AnveshKumar M
Tera Sage
Tera Sage

ServiceNow administrators often need to create new users and assign them the appropriate roles and group memberships. This can be a time-consuming process, especially if the user needs to be granted access to a large number of groups and roles.

 

To make this process easier, you can create a UI action to clone the roles and groups of one user to another user. This UI action can be added to the User form, so that it is easily accessible to administrators.

 

To create this UI Action, I have created an UI Page to use it as a Pop Up and a Script Include to process the request. Follow along to create one for yourself.

 

A. Script Include: To create a Client Callable Script Include,

  1. Navigate to System Definition > Script Includes.
  2. Click New.
  3. Enter a name: CloneUserProfileUtils 
  4. Set the Client Callable to True.
  5. In the Script field, enter the following code and Save.
var CloneUserProfileUtils = Class.create();
CloneUserProfileUtils.prototype = Object.extendsObject(AbstractAjaxProcessor, {

    cloneRolesGroups: function() {
        var usr = this.getParameter("sysparm_usr");
        var usr_ref = this.getParameter("sysparm_usr_ref");
        var override_existing = this.getParameter("sysparm_override_existing") + "";

        if (override_existing === 'true' && !gs.nil(usr)) {
            var clr_roles = this.clearRoles(usr);
            if (!clr_roles)
                return "false";
            var clr_grps = this.clearGroups(usr);
            if (!clr_grps)
                return "false";
        }

        if (!gs.nil(usr) && !gs.nil(usr_ref)) {
            var cpy_grps = this.copyGroups(usr, usr_ref);
            if (!cpy_grps)
                return "false";
			var cpy_roles = this.copyRoles(usr, usr_ref);
            if (!cpy_roles)
                return "false";
        }

        return "true";
    },

    clearRoles: function(usr) {
        try {
            var roleGr = new GlideRecord("sys_user_has_role");
            roleGr.addQuery("user", usr);
            roleGr.addQuery("inherited", false);
            roleGr.query();
            roleGr.deleteMultiple();
        } catch (ex) {
			gs.info("Role remove Error: " + ex);
            return false;
        }
        return true;

    },

    clearGroups: function(usr) {
        try {
            var grpGr = new GlideRecord("sys_user_grmember");
            grpGr.addQuery("user", usr);
            grpGr.query();
            gs.info("Grp RC: " + grpGr.getRowCount());
            grpGr.deleteMultiple();
        } catch (ex) {
			gs.info("Group remove Error: " + ex);
            return false;
        }
        return true;

    },

    copyRoles: function(usr, usr_ref) {
        try {
            var roleGr = new GlideRecord("sys_user_has_role");
            roleGr.addQuery("user", usr_ref);
            roleGr.addQuery("inherited", false);
            roleGr.query();
            while (roleGr._next()) {
                var tgtRoleGr = new GlideRecord("sys_user_has_role");
                tgtRoleGr.addQuery("user", usr);
                tgtRoleGr.addQuery("role", roleGr.getValue("role"));
                tgtRoleGr.query();
				
                if (!tgtRoleGr.hasNext()) {
                    tgtRoleGr.initialize();
                    tgtRoleGr.setValue("user", usr);
                    tgtRoleGr.setValue("role", roleGr.getValue("role"));
                    tgtRoleGr.insert();
                }
            }
        } catch (ex) {
			gs.info("Role copy Error: " + ex);
            return false;
        }
        return true;
    },

    copyGroups: function(usr, usr_ref) {
        try {
            var grpGr = new GlideRecord("sys_user_grmember");
            grpGr.addQuery("user", usr_ref);
            grpGr.query();
            while (grpGr._next()) {
                var tgtGrpGr = new GlideRecord("sys_user_grmember");
                tgtGrpGr.addQuery("user", usr);
                tgtGrpGr.addQuery("group", grpGr.getValue("group"));
                tgtGrpGr.query();

                if (!tgtGrpGr.hasNext()) {
                    tgtGrpGr.initialize();
                    tgtGrpGr.setValue("user", usr);
                    tgtGrpGr.setValue("group", grpGr.getValue("group"));
                    tgtGrpGr.insert();
                }
            }
        } catch (ex) {
			gs.info("Group copy Error: " + ex);
            return false;
        }
        return true;
    },

    type: 'CloneUserProfileUtils'
});

 

B. UI Page: To create an UI Page, follow these steps

  1. Navigate to System UI > UI Pages.
  2. Click New.
  3. Enter a name for the UI page: clone_user_roles_groups
  4. In the Client Script field & HTML field, enter the following code and Save.

Client Script:

function continueOK() {
	var gdw = GlideDialogWindow.get();
	var user_tgt = gdw.getPreference('usr');
	var user_ref = gel('user_ref').value;
	var override_existing = gel('override_existing').value;

	var ga = new GlideAjax("CloneUserProfileUtils");
	ga.addParam("sysparm_name", "cloneRolesGroups");
	ga.addParam("sysparm_usr", user_tgt);
	ga.addParam("sysparm_usr_ref", user_ref);
	ga.addParam("sysparm_override_existing", override_existing);
	ga.getXMLAnswer(processResponse);

	function processResponse(answer){
		if(answer === 'true')
			g_form.addInfoMessage("Roles and Groups cloned successfully.");
		else
			g_form.addErrorMessage("Roles and Groups clone failed.");
			
		GlideDialogWindow.get().destroy();
	}
}
function continueCancel() {
	GlideDialogWindow.get().destroy();
}

 

HTML:

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
   <g:evaluate var="jvar_usr" jelly="true">
      var usr = RP.getWindowProperties().get('usr');
	  usr;
   </g:evaluate>
   <g:evaluate var="jvar_usr_disp" jelly="true">
      var usr1 = RP.getWindowProperties().get('usr');
	  var usr_disp = "";
	  var usrGR = new GlideRecord("sys_user");
	  usrGR.addQuery("sys_id", usr1);
	  usrGR.query();
	  if (usrGR.next()) {
        usr_disp = usrGR.getDisplayValue();
     }
     usr_disp;
   </g:evaluate>
   <br/>
   
   <div class="alert alert-info">
      <strong>Note:</strong> You should elevate to security_admin to copy security_admin role.
   </div>

   <g:ui_form>
	  <br/>
      <table>
         <tr>
            <td style="width:25%">
               <g:form_label>
                  Target User: 
               </g:form_label>
            </td>
            <td style="width:60%">
               <b>${usr_disp}</b><br/>
            </td>
         </tr>				
         <tr>
            <td style="width:25%">
               <g:form_label>
                  Reference User: 
               </g:form_label>
            </td>
            <td style="width:60%">
               <g:ui_reference name="user_ref" id="user_ref" query="active=true" table="sys_user"  />
            </td>
         </tr>
         <tr>
            <td style="width:25%">
               <g:form_label>
                  Override Existing Roles &amp; Groups:
               </g:form_label>
            </td>
            <td style="width:60%">
               <g:ui_checkbox name="override_existing" id="override_existing" value="false"/>
            </td>
         </tr>
		 
      </table>
	  <div id="dialog_buttons" class="clearfix pull-right no_next">
	  	 <g:dialog_buttons_ok_cancel ok_id="submitData" ok="return continueOK()" ok_type="button" ok_text="${gs.getMessage('Clone')}" ok_style_class="btn btn-primary" cancel_type="button" cancel_id="cancelData" cancel_style_class="btn btn-default" cancel="return continueCancel()"/>
	  </div>
   </g:ui_form>
</j:jelly>
 
C. UI Action: To create a UI action, follow these steps:
  1. Navigate to System Definition > UI Actions.
  2. Click New.
  3. Enter a name: Clone Roles and Groups.
  4. Enter an Action name: clone_roles_groups_from_ref_user
  5. Set Show Insert: False, Show Update True, Client: True and Form context menu: True and Form link: True
  6. In the Condition field, enter: gs.hasRole('admin') && current.active == true
  7. In the onClick field, enter: cloneUser()
  8. In the Script field, enter the following code and Save.
function cloneUser() {
	var dialogClass = GlideDialogWindow;
	var dialog = new dialogClass("clone_user_roles_groups");
	dialog.setTitle("Clone Roles & Groups");
	dialog.setPreference("usr",g_form.getUniqueValue());
	dialog.setWidth(800);
	dialog.render();	
}
 

 

Note: See the screenshots attached for quick reference.

 

Now, when you open a User record, you will see the Clone Roles and Groups form context menu and related link. To clone the roles and groups of another user, simply click this button and select the reference user and check Override existing to true if you want to delete existing roles and groups of target user.

 

This UI action can save you a lot of time and effort when creating new users and assigning them the appropriate roles and group memberships.

Comments
praveenhirekudi
Tera Contributor

This is super helpful ..thanks for sharing

Ravi Kand
Tera Contributor

Great job. Appreciate.

Toon6543
Tera Expert

When I do this everything comes up as normal. However, when I click clone roles and groups under my user I get an error stating that the page you are looking for could not be found. Any ideas?

AnveshKumar M
Tera Sage
Tera Sage

@Toon6543 Please check the UI Page name, it should be same in UI Action Script line number 3.

Mark Andreopou1
ServiceNow Employee
ServiceNow Employee

Thanks for your work on this. I'm having an issue, when I launch the action from a user record, it just takes me back to the list of users. It seems like the UI Action isn't launch the UI Page. If I go to the UI Page and click on 'try it', the page launches. I have checked syntax several times and everything matches. Thanks for your help.

clone_user_roles_groups

 

MarkusRobeS
Tera Contributor

Hi, I have the same issue because I missed to add the "sys_user" as table for the UI Action.

DarioH
Giga Explorer

Sir, you are amazing and you have just saved me so much time. Thank you!!

Version history
Last update:
‎11-10-2023 05:08 AM
Updated by:
Contributors