Mark Stanger, Author at ServiceNow Guru https://servicenowguru.com/author/markstanger/ ServiceNow Consulting Scripting Administration Development Tue, 04 Jun 2024 14:08:14 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.2 https://servicenowguru.com/wp-content/uploads/2024/05/cropped-SNGuru-Icon-32x32.png Mark Stanger, Author at ServiceNow Guru https://servicenowguru.com/author/markstanger/ 32 32 Beginning of a New Era at ServiceNow Guru https://servicenowguru.com/announcements/new-era-servicenow-guru/ https://servicenowguru.com/announcements/new-era-servicenow-guru/#comments Fri, 24 May 2024 15:35:06 +0000 https://servicenowguru.com/?p=15861 It's been a whirlwind of a year at ServiceNow Guru! After years of seeing it gather cobwebs, I managed to re-acquire SN Guru from the company I founded, and started the tedious, but somehow cathartic process of migrating files and databases, reviewing old and outdated content, responding to and culling hundreds of old comments, and

The post Beginning of a New Era at ServiceNow Guru appeared first on ServiceNow Guru.

]]>
It’s been a whirlwind of a year at ServiceNow Guru! After years of seeing it gather cobwebs, I managed to re-acquire SN Guru from the company I founded, and started the tedious, but somehow cathartic process of migrating files and databases, reviewing old and outdated content, responding to and culling hundreds of old comments, and re-thinking the future of this labor of love that has become a large part of my ServiceNow legacy. While I discovered a massive amount of work required to get the site back to a state that would match its reputation with many longtime readers, what amazed me most was the value so many of these solutions were still providing to a passionate and supportive ServiceNow community. SN Guru has always been focused on the needs of its readers, with many of the ideas originating from requirements and challenges you faced on your projects, making the articles incredibly relevant over time. I’ve always been grateful for the way that focus on relevance and value has offered me a connection with so many incredible friends and associates over the years.

Since the re-acquisition of SN Guru, we’ve reached several important milestones in the reimagining of the site, including a new brand and logo, and an entire site redesign that has breathed much-needed life into the site. The primary remaining concern has been around re-initiating and maintaining the steady flow of expert-level content that has become the defining feature at SN Guru. It’s clear to me that the ServiceNow platform is simply too expansive for a single person to meaningfully address even a fraction of the possible content, solutions, and leading practices that would be truly helpful to our target audience. With that recognition in mind, I reached out to my network to call for authors to join the site. The response has been both humbling and inspiring!

Today, I’m pleased to announce a new era of ServiceNow Guru innovation with the addition of a world-class team of brilliant ServiceNow architects, consultants, developers, and thought leaders as authors at SN Guru. These “New Gurus” are leading experts on the ServiceNow platform, each distinguished by deep levels of expertise and stellar reputations earned through years in the trenches of ServiceNow implementation and development work in all areas of the platform encompassing literally thousands of product implementations. They come from around the world and from a variety of backgrounds and experiences that are not only inspiring but representative of the ServiceNow community at large. They know what works, and perhaps more importantly, what doesn’t. Over the coming weeks, they’ll begin to unleash a steady stream of expert knowledge to the ServiceNow world that will be unrivaled outside of official ServiceNow learning and community sites. They’ll share the real-world insights that are the “street smarts” companion to the “book smarts” knowledge in the official ServiceNow documentation that SN Guru has always been known for. In addition, we’ll be working to go through the old Guru articles you know and love to ensure they are accurate and up-to-date with the latest ServiceNow releases. You won’t want to miss it!

I invite you to learn more about the new ServiceNow Gurus via their featured profiles on our new ‘ServiceNow Gurus’ page. Their expertise will be available through SN Guru and will be shared via the official SN Guru LinkedIn and Twitter pages initially, with other outlets, and Gurus, coming as we grow. Follow or subscribe to those outlets to receive notifications of each new article, and to stay in the loop about all of the exciting things we’re planning going forward!

The post Beginning of a New Era at ServiceNow Guru appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/announcements/new-era-servicenow-guru/feed/ 2
ServiceNow Guru Author Guide https://servicenowguru.com/authors/servicenow-guru-author-guide/ Thu, 16 May 2024 20:51:40 +0000 https://servicenowguru.com/?p=15581 Welcome, ServiceNow Guru authors! This article is intended to help describe the main components and best practices for authoring a post on ServiceNow Guru. While these guidelines will undoubtedly evolve over time, this guide is based off of guidelines and styles used on the site from its inception and will help ensure the site

The post ServiceNow Guru Author Guide appeared first on ServiceNow Guru.

]]>
Sorry, but you do not have permission to view this content. ]]>
Application Portfolio Management (APM) assessment challenges https://servicenowguru.com/service-now-miscellaneous/application-portfolio-management-apm-assessment-challenges/ Wed, 18 Jan 2023 18:24:56 +0000 http://servicenowguru.com/?p=13173 Like children, I don't think we are supposed to pick our favorite product/application on the ServiceNow platform, so I will simply say Application Portfolio Management (APM) is one of my favorites. The reason for this praise is because APM in my opinion is one of the best products to show the power of the ServiceNow

The post Application Portfolio Management (APM) assessment challenges appeared first on ServiceNow Guru.

]]>
Like children, I don’t think we are supposed to pick our favorite product/application on the ServiceNow platform, so I will simply say Application Portfolio Management (APM) is one of my favorites. The reason for this praise is because APM in my opinion is one of the best products to show the power of the ServiceNow platform. Commercial break over, but if you have not checked out APM take a look at this product and consider putting it on your roadmap.

APM | The Big Picture

https://docs.servicenow.com/en-US/bundle/tokyo-it-business-management/page/product/application-portfolio-management/concept/application-portfolio-management.html

The purpose of this post is to offer advice and potentially some alternatives when building out indicators based on Assessments within APM.

If unfamiliar with assessments, here is a link to the ServiceNow documentation. https://docs.servicenow.com/bundle/tokyo-servicenow-platform/page/administer/assessments/reference/r_Assessments.html

Scoring profiles are made up of one or many indicators (not to be confused with Performance Analytic indicators) and associated with several business applications or capabilities. When assessments are generated for a year/quarter these are typically assigned to a user identified on the business application record such as the “IT Application owner” or “Application portfolio manager”.

The challenge with these assessments is that the collected scores will not populate unless 100% of the application indicators are complete.  For organizations with hundreds and sometimes thousands of applications, one incomplete assessment for one application can impact the application scoring for the entire organization. Meaning the business application scores will not be available to review for that year/quarter until the outstanding assessment is complete and submitted.

There must be a better way!

The first question to ask is, are application assessments absolutely required?

Some alternative options include:

  • Advanced Rationalization
    • Move towards a more advanced scoring profile that does not depend on assessments.
  • Form Values
    • Move assessment-based questions to fields on the business application record and then ensure these are part of the data certification process prior to the scoring cycle. Better yet can these values be derived from existing fields?
      • Careful consideration should be made before adding custom fields to a table in ServiceNow.

If assessments are required, there are also some alternative options.

  • Limit the target
    • Shrink the assessors required to someone like the “Application portfolio manager” who can complete assessments for all applications in a portfolio. This does not scale well for organizations with a large number of business applications.
  • Influence
    • Try to influence assessors to complete tasks on time (carrot or stick).
  • Scripted Solution
    • This is accomplished by changing the indicator type from assessments to a custom script. With a custom script we can pull in the submitted value before all assessments are complete.
    • The question that comes up next is what to do for those unsubmitted assessment scores. Some options include using the last period’s submitted result, last period’s submitted result + a penalty, assume the worst case (worst possible score), or assume the best case (best possible score).
    • For implementation the result is stored in asmt_category_result table, using the source_id as the business application sys_id and the rating field as the submitted value. This rating value can then be included in the payload along with the business application sys_id.

APM can be used for business applications or business capabilities. For simplicity, I assumed business application in the scenario above however, the scenario will hold true for business capabilities as well.

The post Application Portfolio Management (APM) assessment challenges appeared first on ServiceNow Guru.

]]>
Knowledge Translation using Localization Framework and Azure https://servicenowguru.com/knowledge-management/knowledge-translation-using-localization-framework-and-azure/ Wed, 18 Jan 2023 15:38:59 +0000 http://servicenowguru.com/?p=13163 When tasked with the requirement to translate knowledge articles into other languages this can be intimidating especially for those of us that are still working on mastering our first language. Thankfully there is significant help in a new offering in the Tokyo release. What I want to shine a light on is the expanded capabilities

The post Knowledge Translation using Localization Framework and Azure appeared first on ServiceNow Guru.

]]>
When tasked with the requirement to translate knowledge articles into other languages this can be intimidating especially for those of us that are still working on mastering our first language. Thankfully there is significant help in a new offering in the Tokyo release.

What I want to shine a light on is the expanded capabilities of the Localization Framework. Specifically support for Knowledge translation, this is not simply translation management as some of you have seen in the past but a new feature in Tokyo.

https://docs.servicenow.com/bundle/tokyo-platform-administration/page/administer/localization-framework/concept/lf-support-for-kb-articles.html

https://docs.servicenow.com/bundle/tokyo-servicenow-platform/page/product/knowledge-management/concept/bulk-translation.html

The main goal is to provide a fast and efficient way to translate multiple knowledge articles to another supported language.

Once complete we should be able to select the targeted knowledge articles, select Request Translations, select language(s), and then submit. For fulfillment, we are going to look at machine translation using Azure.

For those with a large collection, the maximum number of articles to translate per batch is 200. For large knowledge bases, I recommend coming up with a  strategy around these batches either by category or some other subset to ensure this does not get overwhelming for translation validation later in the process.

Setup

Step 1: Make sure you are not in your PROD instance, and while you are at it make sure your sub-prod instances have different themes (colors) so you and others can easily differentiate.

Step 2: Review dependencies

Knowledge Management Advanced Plugin (com.snc.knowledge_advanced)

    • Consider installing the installer plugin (com.snc.knowledge_advanced.installer) as additional checks and validations are built in for existing articles.

Step 3: Activate Plugins

Step 4: Properties

    • Ensure the property glide.knowman.translation.enable_lf_article_translation is set to true
    • Ensure the property glide.knowman.translation.enable_translation_task is set to false

Step 5: Setup Translation Service

We are going to require a translation service, thankfully there are 3 partially set up upon activation (ServiceNow, Microsoft, and IBM). For the ServiceNow translation service there is no subflow available and no documentation so not sure what that is all about. In this example, I decided to work with MS Azure as I already have an account.

Step 6: Setup localization settings

    • Setup localization fulfiller and manager groups
      • Navigate to System Security > Users and Groups > Groups
      • Create or identify a group to be assigned localization tasks
        • Add the role localization_fulfiller to the identified group
        • Add members to the group, these are your translation validators and each target language should have a group.
      • Create or identify a group to be assigned to the localization project
        • Add the role localization_manager to the identified group
        • Add members to the group
    • Navigate to Localization Framework > Settings
      • Click New to create a new Settings record
      • Setup as shown below using required languages, TMS settings, and email settings
    • A localization framework setting should be created for each target language as this is how the tasks are fulfilled.

Translation process

    • Navigate to Knowledge > Article > All
    • Select a few articles with checkboxes on the left side of the record
    • Click the “Request Translations” UI action/button in the top right
    • Select the target translation(s) and click submit
    • Navigate to Localization Framework > My Projects
    • Click “All” to clear the filter and view all projects
    • Open the most recent project (highest number)
    • Notice the related lists for Localization Requested Items and Localization Tasks.
    • Open the Localization Task, which should look like this…
    • Click the Translate button in the top right, and review the translations. Notice the status of the translations.
      • From here we can expand and update the translation or click Publish Translations which will create the Knowledge articles.
      • This page/interface is controlled by the Localization Framework settings configured above. Try changing those settings to see what is added or removed. For example, there is no approval as we selected the Auto Translation –> Publish for the Workflow.
    • After reviewing all, click Publish Translations in the top right.
    • Navigate to Knowledge > Article > All
    • Find the most recent article which should be the newly created translated article.

Want more good news? You have the built-in artifacts which is great but you can also extend the framework, see the link below for more: https://www.servicenow.com/community/international-localization/extending-the-localization-framework-to-portal-announcements/ta-p/2326792

 

The post Knowledge Translation using Localization Framework and Azure appeared first on ServiceNow Guru.

]]>
Localization framework fulfillment (LP, LRITM, LFTASK) https://servicenowguru.com/system-definition/localization-framework-fulfillment-lp-lritm-lftask/ Wed, 18 Jan 2023 15:26:39 +0000 http://servicenowguru.com/?p=13161 Recently I dove into the Localization Framework, noticed some new tables, made some incorrect initial assumptions, and came out with an understanding of the table structure that I could not find consolidated on the documentation site. Number Prefix Label Name Extends LP Localization Project sn_lf_project Task LRITM Localization Requested Item sn_lf_requested_item LFTASK Localization Task sn_lf_task

The post Localization framework fulfillment (LP, LRITM, LFTASK) appeared first on ServiceNow Guru.

]]>
Recently I dove into the Localization Framework, noticed some new tables, made some incorrect initial assumptions, and came out with an understanding of the table structure that I could not find consolidated on the documentation site.

Number Prefix Label Name Extends
LP Localization Project sn_lf_project Task
LRITM Localization Requested Item sn_lf_requested_item
LFTASK Localization Task sn_lf_task Task

 

You might think as I did that this data model aligns to request fulfillment with LFTASK the same as SCTASK, LRITM as RITM, and LP as REQ however this is incorrect.

Localization Projects (LP)

Are groupings of multiple requested items (LRITM). Localization Projects are assigned to a group with the localization_manager role and “assigned to” a member of the group to manage this effort. This table extends the task table directly. Localization Projects are not required in localization fulfillment.

https://docs.servicenow.com/bundle/tokyo-platform-administration/page/administer/localization-framework/concept/localization-projects.html

Module

Localization Framework > My Projects

 

Localization Requested Items (LRITM)

Can be added to a project to allow fulfillers to translate items in bulk. Localization Requested Items can be added to a project after they are created and does not need to be done during creation. The Localization Requested Item does not extend task and links through the document id to the target artifact record (knowledge, catalog item, VA topic, etc). Localization Requested Items link to Localization Tasks for translation and are not assigned or actioned directly.

https://docs.servicenow.com/bundle/tokyo-platform-administration/page/administer/localization-framework/task/add-lritm-to-project.html

Module

Localization Framework > My Requested Items

 

Localization Tasks (LFTask)

Are actionable tasks per target language for localization fulfillers with the actions being “Verify Translations” and “Translate”. Localization Tasks directly extend the task table and are related to Localization projects. Localization fulfillment and approval is well documented in the links below.

Fulfillment – https://docs.servicenow.com/bundle/tokyo-platform-administration/page/administer/localization-framework/task/fulfill-localization-task.html

Approval – https://docs.servicenow.com/bundle/tokyo-platform-administration/page/administer/localization-framework/task/approve-localization-task.html

Module

Localization Framework > My Tasks

 

Links

Localization Framework: https://docs.servicenow.com/bundle/tokyo-platform-administration/page/administer/localization-framework/concept/localization-framework.html

States: https://docs.servicenow.com/bundle/tokyo-platform-administration/page/administer/localization-framework/reference/localization-task-states.html

 

For those that like a picture, here is a representation of the tables and corresponding relationships.

The post Localization framework fulfillment (LP, LRITM, LFTASK) appeared first on ServiceNow Guru.

]]>
GlideDialogWindow: Advanced Popups Using UI Pages https://servicenowguru.com/system-ui/glidedialogwindow-advanced-popups-ui-pages/ https://servicenowguru.com/system-ui/glidedialogwindow-advanced-popups-ui-pages/#comments Wed, 23 Jun 2021 14:00:25 +0000 https://servicenowguru.wpengine.com/?p=2060 This article is the 3rd in a series of posts explaining the use of ‘GlideDialog’ in ServiceNow. If you want to see all of the articles I’ve written about GlideDialogWindow and popups in ServiceNow just use the tags at the bottom of this article. In this article I’ll show you how you can use GlideDialogWindow

The post GlideDialogWindow: Advanced Popups Using UI Pages appeared first on ServiceNow Guru.

]]>
This article is the 3rd in a series of posts explaining the use of ‘GlideDialog’ in ServiceNow. If you want to see all of the articles I’ve written about GlideDialogWindow and popups in ServiceNow just use the tags at the bottom of this article.

In this article I’ll show you how you can use GlideDialogWindow to pop open a dialog containing any custom UI Page information you want. I’ll also show how you can pass information into those dialogs, and how you can return information from those dialogs back to the standard form that initiated the dialog. These dialogs can be initiated from any place where you can use client scripts…client scripts, UI Macros, UI Actions, etc.

The only warning I’ll give here is this: While it’s very easy to pop open a dialog window using this method, the real work happens in the UI Page contained in the dialog. The purpose of this post is not to explain the complexities of creating your own UI Pages in ServiceNow. Until I get a chance to write about those, the best recommendation I can give you would be to take a look at the UI Pages you’ll find out-of-box in your system.


The example I’ll use here is based on one that a ServiceNow developer wrote as an example. It’s not very fancy, but it’s simple enough to show how things work without adding a bunch of confusing elements. It simply opens a dialog with information populated from the form and returns information from the dialog to the form.

The first piece of this solution is to set up some mechanism to trigger your GlideDialogWindow. For this example, I’ve chosen to use a UI Action button. Here are the details of the button. The comments in the script explain how to initialize the dialog and pass parameters on to your UI Page to populate information there.

‘Comments Dialog’ UI Action
Name: Comments Dialog
Table: Incident
Action name: comments_dialog
Form Button: True
Client: True
Onclick: commentsDialog()
Script:

function commentsDialog() {
//Get the values to pass into the dialog
var comments_text = g_form.getValue("comments");
var short_text = g_form.getValue("short_description");//Initialize and open the Dialog Window
var dialog = new GlideDialogWindow("task_comments_dialog"); //Render the dialog containing the UI Page 'task_comments_dialog'
dialog.setTitle("Add Task Comments"); //Set the dialog title
dialog.setPreference("comments_text", comments_text); //Pass in comments for use in the dialog
dialog.setPreference("short_text", short_text); //Pass in short description for use in the dialog
dialog.render(); //Open the dialog
}

Once you have your UI Action set up to trigger the dialog, you need to make sure that you have the correctly-named UI Page to display in the dialog. In the script above, we used ‘var dialog = new GlideDialogWindow(“task_comments_dialog”);’ to initialize a GlideDialogWindow and point to the ‘task_comments_dialog’ UI Page. Here’s what that page looks like. The comments in the HTML below explain each piece of the UI Page. The client script portion of the UI Page is used to validate the input on submission of the dialog form. If validation passes, the value of the ‘Comments’ field on the dialog is passed to the ‘Comments’ field on the original form.

‘task_comments_dialog’ UI Page
HTML

<table width="100%">
<tbody>
<tr id="description_row" valign="top">
<td colspan="2">${jvar_short_text}</td>
</tr>
<tr>
<td colspan="2"></td>
</tr>
</tbody>
</table>

Client script

function validateComments() {
//Gets called if the 'OK' dialog button is clicked
//Make sure dialog comments are not empty
var comments = gel("dial_comments").value;
comments = trim(comments);
if (comments == "") {
//If comments are empty stop submission
alert("Please provide comments to submit the dialog.");
return false;
}
//If comments are not empty do this...
GlideDialogWindow.get().destroy(); //Close the dialog window
g_form.setValue("comments", comments); //Set the 'Comments' field with comments in the dialog
}
If you’re interested in learning more about how to use this method I highly recommend taking a look at a great example that you can find right in your ServiceNow instance. The ‘task_assignment_group_choose_by_person’ UI Macro can be added to the ‘assignment_group’ field on any task form by adding the ‘ref_contributions=task_assignment_group_choose_by_person’ attribute to the dictionary entry for that field. The UI Macro shows up as an icon that displays a GlideDialogWindow containing the contents of the ‘task_assignment_group_dialog’ UI Page when it is clicked. The UI Page lets the user search for and select an assignment group to populate on the form.

The post GlideDialogWindow: Advanced Popups Using UI Pages appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/system-ui/glidedialogwindow-advanced-popups-ui-pages/feed/ 47
User Object Cheat Sheet https://servicenowguru.com/scripting/user-object-cheat-sheet/ https://servicenowguru.com/scripting/user-object-cheat-sheet/#comments Wed, 23 Jun 2021 13:02:52 +0000 https://servicenowguru.wpengine.com/?p=1079 No 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

The post User Object Cheat Sheet appeared first on ServiceNow Guru.

]]>
No 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/MethodReturn ValueUsage
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.
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
gs.getUser().getRecord().getValue('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).

Property/MethodReturn value
g_user.userNameUser name of the current user e.g. employee
g_user.firstNameFirst name of the current user e.g. Joe
g_user.lastNameLast name of the current user e.g. Employee
g_user.userIDsys_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 grpName = 'YOURGROUPNAMEHERE';
var usrID = g_user.userID; //Get current user ID
var grp = new GlideRecord('sys_user_grmember');
grp.addQuery('group.name', grpName);
grp.addQuery('user', usrID);
grp.query(groupMemberCallback);

function groupMemberCallback(grp){
//If user is a member of selected group
if(grp.next()){
//Do something
alert('Is a member');
}
else{
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');
gr.get(g_user.userID);
var title = gr.title;
alert(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 docs site.

The post User Object Cheat Sheet appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/scripting/user-object-cheat-sheet/feed/ 30
GlideRecord Query Cheat Sheet https://servicenowguru.com/scripting/gliderecord-query-cheat-sheet/ https://servicenowguru.com/scripting/gliderecord-query-cheat-sheet/#comments Thu, 20 May 2021 11:37:55 +0000 https://servicenowguru.wpengine.com/?p=1016 I doubt if there’s a single concept in Service-now that is more valuable to understand than how to use GlideRecord methods to query, insert, update, and delete records in your system. These methods have a wide variety of uses and are found at the heart of many of the business rules, UI actions, and scheduled

The post GlideRecord Query Cheat Sheet appeared first on ServiceNow Guru.

]]>
I doubt if there’s a single concept in Service-now that is more valuable to understand than how to use GlideRecord methods to query, insert, update, and delete records in your system. These methods have a wide variety of uses and are found at the heart of many of the business rules, UI actions, and scheduled job scripts that are essential to tie together your organization’s processes in your Service-now instance.

While the content of this post isn’t new information (additional examples can be found on the Service-now wiki), my aim is to provide a single page of information containing some common examples of these methods as a reference. This is an excellent page to keep bookmarked!

Note: These methods are designed for use in server-side JavaScript (everything EXCEPT client scripts and UI policies). In some rare cases, it may be necessary to perform a query from a client-side javascript (client script or UI policy). The few methods below that can be used in client-side JavaScript have been noted below.

Query

Can also be used in Client scripts and UI policies.

A standard GlideRecord query follows this format.

var gr = new GlideRecord('incident'); //Indicate the table to query from
//The 'addQuery' line allows you to restrict the query to the field/value pairs specified (optional)
//gr.addQuery('active', true);
gr.query(); //Execute the query
while (gr.next()) { //While the recordset contains records, iterate through them
//Do something with the records returned
if(gr.category == 'software'){
gs.log('Category is ' + gr.category);
}
}
UPDATE: This same function applies to client-side GlideRecord queries! If at all possible, you should use an asynchronous query from the client. See this post for details.

var gr = new GlideRecord('sys_user');
gr.addQuery('name', 'Joe Employee');
gr.query(myCallbackFunction); //Execute the query with callback function//After the server returns the query recordset, continue here
function myCallbackFunction(gr){
while (gr.next()) { //While the recordset contains records, iterate through them
alert(gr.user_name);
}
}

‘Get’ Query Shortcut (used to get a single GlideRecord)

Can also be used in Client scripts and UI policies IF YOU ARE GETTING A RECORD BY SYS_ID.

The ‘get’ method is a great way to return a single record when you know the sys_id of that record.

var gr = new GlideRecord('incident');
gr.get(sys_id_of_record_here);
//Do something with the record returned
if(gr.category == 'software'){
gs.log('Category is ' + gr.category);
}

You can also query for a specific field/value pair. The ‘get’ method returns the first record in the result set.

//Find the first active incident record
var gr = new GlideRecord('incident');
if(gr.get('active', true)){
//Do something with the record returned
gs.log('Category is ' + gr.category);
}
‘getRefRecord’ Query Shortcut (used to get a single GlideRecord referenced in a reference field)
The ‘getRefRecord’ method can be used as a shortcut to query a record populated in a reference field on a record.

var caller = current.caller_id.getRefRecord(); //Returns the GlideRecord for the value populated in the 'caller_id' field
caller.email = 'test@test.com';
caller.update();
‘OR’ Query
The standard ‘addQuery’ parameter acts like an ‘and’ condition in your query. This example shows how you can add ‘or’ conditions to your query.

//Find all incidents with a priority of 1 or 2
var gr = new GlideRecord('incident');
var grOR = gr.addQuery('priority', 1);
grOR.addOrCondition('priority', 2);
gr.query();
while (gr.next()) {
//Do something with the records returned
if(gr.category == 'software'){
gs.log('Category is ' + gr.category);
}
}

Note that you can also chain your ‘OR’ condition as well, which is usually simpler

//Find all incidents with a priority of 1 or 2
var gr = new GlideRecord('incident');
gr.addQuery('priority', 1).addOrCondition('priority', 2);
gr.query();
Insert
Inserts are performed in the same way as queries except you need to replace the ‘query()’ line with an ‘initialize()’ line as shown here.

//Create a new Incident record and populate the fields with the values below
var gr = new GlideRecord('incident');
gr.initialize();
gr.short_description = 'Network problem';
gr.category = 'software';
gr.caller_id.setDisplayValue('Joe Employee');
gr.insert();
Update
You can perform updates on one or many records simply by querying the records, setting the appropriate values on those records, and calling ‘update()’ for each record.

//Find all active incident records and make them inactive
var gr = new GlideRecord('incident');
gr.addQuery('active',true);
gr.query();
while (gr.next()) {
gr.active = false;
gr.update();
}
Delete
Delete records by performing a glideRecord query and then using the ‘deleteRecord’ method.

//Find all inactive incident records and delete them one-by-one
var gr = new GlideRecord('incident');
gr.addQuery('active',false);
gr.query();
while (gr.next()) {
//Delete each record in the query result set
gr.deleteRecord();
}
deleteMultiple Shortcut
If you are deleting multiple records then the ‘deleteMultiple’ method can be used as a shortcut

//Find all inactive incidents and delete them all at once
var gr = new GlideRecord('incident');
gr.addQuery('active', false);
gr.deleteMultiple(); //Deletes all records in the record set

addEncodedQuery

CANNOT be used in Client scripts and UI policies! Use ‘addQuery(YOURENCODEDQUERYHERE)’ instead.

An alternative to a standard query is to use an encoded query to create your query string instead of using ‘addQuery’ and ‘addOrCondition’ statements. An easy way to identify the encoded query string to use is to create a filter or a module with the query parameters you want to use, and then hover over the link or breadcrumb and look at the URL. The part of the URL after ‘sysparm_query=’ is the encoded query for that link.
So if I had a URL that looked like this…
https://demo.service-now.com/incident_list.do?sysparm_query=active=true^category=software^ORcategory=hardware

My encoded query string would be this…
active=true^category=software^ORcategory=hardware

I could build that encoded query string and use it in a query like this…

//Find all active incidents where the category is software or hardware
var gr = new GlideRecord('incident');
var strQuery = 'active=true';
strQuery = strQuery + '^category=software';
strQuery = strQuery + '^ORcategory=hardware';
gr.addEncodedQuery(strQuery);
gr.query();
GlideAggregate
GlideAggregate is actually an extension of the GlideRecord object. It allows you to perform the following aggregations on query recordsets…
-COUNT
-SUM
-MIN
-MAX
-AVG

//Find all active incidents and log a count of records to the system log
var gr = new GlideAggregate('incident');
gr.addQuery('active', true);
gr.addAggregate('COUNT');
gr.query();
var incidents = 0;
if (gr.next()){
incidents = gr.getAggregate('COUNT');
gs.log('Active incident count: ' + incidents);
}
orderBy/orderByDesc
You can order the results of your recordset by using ‘orderBy’ and/or ‘orderByDesc’ as shown below.

//Find all active incidents and order the results ascending by category then descending by created date
var gr = new GlideRecord('incident');
gr.addQuery('active', true);
gr.orderBy('category');
gr.orderByDesc('sys_created_on');
gr.query();
addNullQuery/addNotNullQuery
‘addNullQuery’ and ‘addNotNullQuery’ can be used to search for empty (or not empty) values

//Find all incidents where the Short Description is empty
var gr = new GlideRecord('incident');
gr.addNullQuery('short_description');
gr.query();
//Find all incidents where the Short Description is not empty
var gr = new GlideRecord('incident');
gr.addNotNullQuery('short_description');
gr.query();
getRowCount
‘getRowCount’ is used to get the number of results returned

//Log the number of records returned by the query
var gr = new GlideRecord('incident');
gr.addQuery('category', 'software');
gr.query();
gs.log('Incident count: ' + gr.getRowCount());
Although ‘getRowCount’ isn’t available client-side, you can return the number of results in a client-side GlideRecord query by using ‘rows.length’ as shown here…
//Log the number of records returned by the query
var gr = new GlideRecord('incident');
gr.addQuery('category', 'software');
gr.query();
alert('Incident count: ' + gr.rows.length);
setLimit
‘setLimit’ can be used to limit the number of results returned

//Find the last 10 incidents created
var gr = new GlideRecord('incident');
gr.orderByDesc('sys_created_on');
gr.setLimit(10);
gr.query();
chooseWindow
The chooseWindow(first,last) method lets you set the first and last row number that you want to retrieve and is typical for chunking-type operations. The rows for any given query result are numbered 0..(n-1), where there are n rows. The first parameter is the row number of the first result you’ll get. The second parameter is the number of the row after the last row to be returned. In the example below, the parameters (10, 20) will cause 10 rows to be returned: rows 10..19, inclusive.

//Find the last 10 incidents created
var gr = new GlideRecord('incident');
gr.orderByDesc('sys_created_on');
gr.chooseWindow(10, 20);
gr.query();
setWorkflow
‘setWorkflow’ is used to enable/disable the running of any business rules that may be triggered by a particular update.

//Change the category of all 'software' incidents to 'hardware' without triggering business rules on updated records
var gr = new GlideRecord('incident');
gr.addQuery('category', 'software');
gr.query();
while(gr.next()){
gr.category = 'hardware';
gr.setWorkflow(false);
gr.update();
}
autoSysFields
‘autoSysFields’ is used to disable the update of ‘sys’ fields (Updated, Created, etc.) for a particular update. This really is only used in special situations. The primary example is when you need to perform a mass update of records to true up some of the data but want to retain the original update timestamps, etc.

//Change the category of all 'software' incidents to 'hardware' without updating sys fields
var gr = new GlideRecord('incident');
gr.addQuery('category', 'software');
gr.query();
while(gr.next()){
gr.category = 'hardware';
gr.autoSysFields(false);
gr.update();
}
setForceUpdate
‘setForceUpdate’ is used to update records without having to change a value on that record to get the update to execute. ‘setForceUpdate’ is particularly useful in situations where you need to force the recalculation of a calculated field for all records in a table or when you need to run business rules against all records in a table but don’t want to have to change a value on the records.
This method is often used with ‘setWorkflow’ and ‘autoSysFields’ as shown below.

//Force an update to all User records without changing field values
var gr = new GlideRecord('sys_user');
gr.query();
while (gr.next()) {
gr.setWorkflow(false); //Do not run business rules
gr.autoSysFields(false); //Do not update system fields
gr.setForceUpdate(true); //Force the update
gr.update();
}
JavaScript Operators
The following operators can be used in addition to the standard field/value query searching shown above…
OperatorDescriptionCode
=Field value must be equal to the value supplied.addQuery('priority', '=', 3);
>Field must be greater than the value supplied.addQuery('priority', '>', 3);
<Field must be less than the value supplied.addQuery('priority', '<', 3);
>=Field must be equal to or greater than the value supplied.addQuery('priority', '>=', 3);
<=Field must be equal to or less than the value supplied.addQuery('priority', '<=', 3);
!=Field must not equal the value supplied.addQuery('priority', '!=', 3);
STARTSWITHField must start with the value supplied. The example shown on the right will get all records where the short_description field starts with the text 'Error'.addQuery('short_description', 'STARTSWITH', 'Error');
ENDSWITHField must end with the value supplied. The example shown on the right will get all records where the short_description field ends with text 'Error'.addQuery('short_description', 'ENDSWITH', 'Error');
CONTAINSField must contain the value supplied anywhere in the field. The example shown on the right will get all records where the short_description field contains the text 'Error' anywhere in the field.addQuery('short_description', 'CONTAINS', 'Error');
DOES NOT CONTAINField must not contain the value supplied anywhere in the field. The example shown on the right will get all records where the short_description field does not contain the text 'Error' anywhere in the field.addQuery('short_description', 'DOES NOT CONTAIN', 'Error');
INField must contain the value supplied anywhere in the string provided.addQuery('sys_id', 'IN', '0331ddb40a0a3c0e40c83e9f7520f860,032ebb5a0a0a3c0e2e2204a495526dce');
INSTANCEOFRetrieves only records of a specified class for tables which are extended. For example, to search for configuration items (cmdb_ci table) you many want to retrieve all configuration items that are have are classified as computers. The code uses the INSTANCEOF operator to query for those records.addQuery('sys_class_name', 'INSTANCEOF', 'cmdb_ci_computer');

The post GlideRecord Query Cheat Sheet appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/scripting/gliderecord-query-cheat-sheet/feed/ 49
Client & Server Code in One UI Action https://servicenowguru.com/ui-actions-system-ui/client-server-code-ui-action/ https://servicenowguru.com/ui-actions-system-ui/client-server-code-ui-action/#comments Thu, 20 May 2021 10:45:36 +0000 https://servicenowguru.wpengine.com/?p=1962 Most Service-now administrators and consultants know how to configure and use UI Actions. UI Actions are UI elements that can show up on a form or a list as a button, link, or context menu. When these UI elements are clicked they execute some JavaScript. Most of the time UI Actions are used to perform

The post Client & Server Code in One UI Action appeared first on ServiceNow Guru.

]]>
Most Service-now administrators and consultants know how to configure and use UI Actions. UI Actions are UI elements that can show up on a form or a list as a button, link, or context menu. When these UI elements are clicked they execute some JavaScript. Most of the time UI Actions are used to perform some server-side update to a record or records. In other cases, you can use the ‘Client’ checkbox on the UI Action record to execute some client-side JavaScript (including checking for mandatory fields).

But what if you need to do both? The classic case is when you want to click a button to make an update to a record, but only if the user has provided the correct input first. An example would be a ‘Reopen Incident’ button that changes the state on an incident record from ‘Resolved’ to ‘Active’. Usually you want to require the user to provide some sort of comment or additional information explaining why they are reopening the ticket. The problem is that you don’t always want the ‘Comments’ field to be mandatory so the validation needs to happen at the time the ‘Reopen Incident’ button gets clicked. Validation of mandatory fields needs to happen client-side but the update to your record needs to happen server-side. How can you accomplish both of these things with a single UI Action? This article shows you how.



The basic format for using a Client Script and Business Rule in the same UI Action looks something like this…

UI Action Template
Name: -Button Name-
Action name: -button_action_name- (Should be unique per button on form and gets called from the UI Action script)
Client: True (MUST be checked)
Form button/Form Context Menu/Form Link: (UI Action must be one of these ‘Form’ types)
Onclick: -runClientCode();- (Points to the function in your script that should be run when the UI Action gets clicked)
Script:

//Client-side 'onclick' function
function runClientCode(){
if( == false){
return false; //Abort submission
}
//Call the UI Action and skip the 'onclick' function
gsftSubmit(null, g_form.getFormElement(), ''); //MUST call the 'Action name' set in this UI Action
}//Code that runs without 'onclick'
//Ensure call to server-side function with no browser errors
if(typeof window == 'undefined')
runBusRuleCode();//Server-side function
function runBusRuleCode(){
current. = ;
current.update();
gs.addInfoMessage('You did it!');
action.setRedirectURL(current);
}

So why does this work? I had to go to a Service-now developer to find out. The reason is that UI Actions can run scripts at two different times. The first time is when the UI Action gets clicked. When you define a ‘Client’ UI Action you also give that UI Action the name of a function in your ‘Script’ field to execute. This function has to be called explicitly (through the ‘onclick’ event) or it doesn’t run at all.
The second time is on the way to the server. This is how any UI Action without the ‘Client’ checkbox selected gets run. On the way to the server the entire UI Action script gets executed regardless of whether or not the ‘Client’ checkbox is checked. What this means is that any script you include in your UI Action that isn’t enclosed in a function will be run on the way to the server. The script above takes advantage of this fact by making a specific call to the ‘Client’ function, performing client-side validation, and then the UI Action calls itself if the client-side validation passes.
When the UI Action calls itself it bypasses the ‘onclick’ function because the button didn’t get clicked the second time. So the script continues to the first point where there is something to execute. At that point you can call your Server-side function! The only thing you need to be careful of is that you only call the Server-side function if the script isn’t running in the client anymore. That’s what the check in the middle does…and eliminates any browser errors saying that ‘current’ (or any other Server-side function or object) isn’t defined.

Here is a solution I’ve used in the past to give users the ability to reopen an incident record. The solution uses a UI Action button to check if the ‘Comments’ field has been filled in (this is the ‘Client-side’ portion). If the validation passes, then the incident record gets updated.

Reopen Incident UI Action

Note that this script uses the ‘State’ field rather than the ‘Incident State’ field. In my opinion, it is much better to consolidate all of your state fields into one using the ‘State’ field at the task level as described here.

Name: Reopen Incident
Action name: reopen_incident
Client: True
Form button: True
Onclick: reopen();
Condition: current.state == 6
Script:

//Client-side 'onclick' function
function reopen(){
if(g_form.getValue('comments') == ''){
//Remove any existing field message, set comments mandatory, and show a new field message
g_form.hideFieldMsg('comments');
g_form.setMandatory('comments', true);
g_form.showFieldMsg('comments','Comments are mandatory when reopening an Incident.','error');
return false; //Abort submission
}
//Call the UI Action and skip the 'onclick' function
gsftSubmit(null, g_form.getFormElement(), 'reopen_incident'); //MUST call the 'Action name' set in this UI Action
}

//Code that runs without 'onclick'
//Ensure call to server-side function with no browser errors
if(typeof window == 'undefined')
serverReopen();

function serverReopen(){
//Set the 'State' to 'Active', update and reload the record
current.state = 2;
current.update();
gs.addInfoMessage('Incident ' + current.number + ' reopened.');
action.setRedirectURL(current);
}

The post Client & Server Code in One UI Action appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/ui-actions-system-ui/client-server-code-ui-action/feed/ 59
The Final ‘Work Note’ – Goodbye From ServiceNow Guru https://servicenowguru.com/service-now-general-knowledge/final-work-note/ https://servicenowguru.com/service-now-general-knowledge/final-work-note/#comments Fri, 05 May 2017 12:42:29 +0000 https://servicenowguru.wpengine.com/?p=12553 When I started ServiceNow Guru back in 2009 I never dreamed that it would find the success that it has. With the ServiceNow wiki still in its infancy and really no place to store common configurations or lessons learned, I simply wanted to create a place to capture the cool stuff that I was building

The post The Final ‘Work Note’ – Goodbye From ServiceNow Guru appeared first on ServiceNow Guru.

]]>
When I started ServiceNow Guru back in 2009 I never dreamed that it would find the success that it has. With the ServiceNow wiki still in its infancy and really no place to store common configurations or lessons learned, I simply wanted to create a place to capture the cool stuff that I was building so that I could re-use it for my next client engagement or share it with a colleague. Since then ServiceNow Guru has grown considerably, with a significant reputation in the ServiceNow ecosystem and drawing thousands of visits every day from around the world. While I still use it as my primary documentation source for the common configurations I do every day, the best part about ServiceNow Guru is that it has also become that type of resource for many of you (some of whom I’ve never met in person) that I now consider my friends.

Original SNCGuru Logo

There’s no doubt that ServiceNow has been (and continues to be) the proverbial “rising tide that lifts all boats” and I’ll forever consider it a blessing to have been introduced to this technology during its early days. There are so many people that helped me (both ServiceNow employees and clients) during those years as an administrator and consultant at ServiceNow. The contents of this site are really a giant collection of your great ideas over the years! Thank you to Michael Brown for giving me my first full-time job in the IT world, Matt Holetz for hiring me as a wide-eyed recent college graduate with a grand total of 8 weeks of ServiceNow experience and trusting me to handle full enterprise implementations on my own, and countless clients and consultants along the way. ServiceNow Guru ended up being the perfect launching pad for Crossfuze a few years later and has continued to help us be successful as a ServiceNow implementation partner. James Farrer (who is an absolute ServiceNow wizard) and Darwin Nielsen (who ran the whole business for over 3 years) were crazy enough to join us before we were even a viable company and have both been instrumental in helping Crossfuze to evolve into the leading consulting organization it is today.

There’s nobody I need to thank more than Jacob Andersen, who followed me to ServiceNow and co-founded Crossfuze with me just over 5 years ago. It’s not much of a secret to anybody who knows both of us, but he’s way more talented technically with ServiceNow than I am and I’m fortunate to have been able to lean on him for so long. Although there’s no doubt both of us wanted to be successful, more than anything we were completely addicted to the ServiceNow technology and loved making our clients happy. It’s a pretty simple formula, but it worked pretty well for us.

Looking back on this journey over the past several months and looking forward to some other priorities and goals in my life has led me to the realization that it’s time for me to step away from the ServiceNow world for a while. I’m anxious to spend more time with my wife and 5 kids at home and consider future opportunities.

Knowledge17 will mark my last week with Crossfuze and will also be a fresh start for ServiceNow Guru with a transfer of ownership and management to Crossfuze. With Chris Howard and the Crossfuze ServiceNow team at the helm, I can’t think of a better place to leave it. Alhough I’ll be stepping away, I’m confident that it will be in good hands and will continue to be a valuable source of quality ServiceNow technical content for years to come.

Thanks to all of you who have helped me in any way to make ServiceNow Guru a success. Every comment, backlink, like, thank you, and kind word helped to drive me forward each day. Knowing that my work was helping people to find success in their own lives and careers and finding innovative ways to solve common ServiceNow problems has fueled my desire to keep this site going for so many years. I wish all of you continued success in whatever ServiceNow adventures lie before you! Feel free to reach out to me through my LinkedIn profile if you’d like to keep in touch!

Mark Stanger

The post The Final ‘Work Note’ – Goodbye From ServiceNow Guru appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/service-now-general-knowledge/final-work-note/feed/ 57