Demystifying ServiceNow Client Scripts: A Deep Dive
Welcome to this in-depth exploration of ServiceNow client scripts! If you’ve been working with ServiceNow for a while, you’ve undoubtedly encountered the power and flexibility of client-side scripting. From making forms dynamic to providing real-time user feedback, client scripts are the backbone of a responsive and intuitive user experience. In this article, we’ll break down the different types of client scripts, their use cases, and best practices, drawing on real-world scenarios and insights from seasoned ServiceNow professionals.
As someone who has journeyed through various ServiceNow versions, from Rome and San Diego all the way to the latest Washington DC release, I’ve seen firsthand how these scripting capabilities have evolved. My goal here is to provide you with practical, human-like explanations that go beyond just syntax, helping you understand the ‘why’ and ‘how’ of effective client scripting.
Understanding the Foundation: User, Group, and Permissions
Before we dive into the specifics of client scripts, it’s crucial to grasp the fundamental concepts of user management and permissions within ServiceNow. These concepts often influence how client scripts are designed and implemented.
User and Group Management in ServiceNow
At the core of ServiceNow’s access control are users and groups. Users are individual accounts, and groups are collections of users. This hierarchy is fundamental to managing permissions efficiently.
- User Table: The primary table storing user information is
sys_user. - Group Member Table: The relationship between users and groups is managed in the
sys_user_grmembertable.
Managing Permissions: Roles and Best Practices
Permissions in ServiceNow are primarily managed through roles. Users and groups can be assigned roles, which then grant access to specific functionalities and data. A key best practice is to leverage groups for role assignments.
Why is this a best practice? Imagine an employee leaves an organization. If their permissions are tied directly to their user account, you’d have to manually remove each role. However, if their permissions are granted through group memberships, simply removing them from the relevant group automatically revokes all associated roles and permissions. This drastically simplifies administration and reduces the risk of orphaned access.
Creating User and Group Accounts via Script: For automation purposes, you can create users and groups using GlideRecord:
var userGr = new GlideRecord(‘sys_user’);
userGr.initialize();
userGr.username = ‘jdoe’;
userGr.firstname = ‘John’;
userGr.lastName = ‘Doe’;
userGr.email = ‘jdoe@example.com’;
userGr.insert();
// Creating a Group
var newGr = new GlideRecord(‘sys_user_group’);
newGr.initialize();
newGr.name = ‘testing’;
// Assuming ‘manager’ is a reference field to sys_user
newGr.manager = ‘62826bf03710200044e0bfc8bcbe5df1’;
newGr.email = ‘testing@tcs.com’;
newGr.description = ‘test’;
newGr.insert();
Assigning Roles via Script
Roles are linked to users and groups through specific tables:
- User Roles: Stored in
sys_user_has_role. - Group Roles: Stored in
sys_group_has_role.
var userRole = new GlideRecord(‘sys_user_has_role’);
userRole.setValue(‘user’, ‘62826bf03710200044e0bfc8bcbe5df1’); // Sys ID of the user
userRole.setValue(‘role’, ‘2831a114c611228501d4ea6c309d626d’); // Sys ID of the role
userRole.insert();
// Adding a Role to a Group
var grpRole = new GlideRecord(‘sys_group_has_role’);
grpRole.setValue(‘group’, ‘477a05d153013010b846ddeeff7b1225’); // Sys ID of the group
grpRole.setValue(‘role’, ‘2831a114c611228501d4ea6c309d626d’); // Sys ID of the role
grpRole.insert();
User Delegation: Working on Behalf of Others
User delegation is a powerful feature that allows one user to perform tasks on behalf of another. This is invaluable when a user is unavailable, such as on vacation.
What it means: A delegated user can access resources and perform actions that the original user would normally be able to. For instance, an employee on leave can delegate their approval tasks to a colleague, ensuring workflows remain uninterrupted.
How it’s set up: This is configured within the original user’s record. Scroll down to the ‘Delegates’ related list, where you can specify the delegate’s name, the start and end dates of the delegation, and the specific permissions they will have (assignments, notifications, approvals).
Adding and Removing Group Members via Script
Managing group membership programmatically is a common requirement:
var grMem = new GlideRecord(‘sys_user_grmember’);
grMem.user = ‘62826bf03710200044e0bfc8bcbe5df1’; // Sys ID of the user
grMem.group = ‘477a05d153013010b846ddeeff7b1225’; // Sys ID of the group
grMem.insert();
// Removing a Group Member
var grMem = new GlideRecord(‘sys_user_grmember’);
grMem.addQuery(‘user’, ‘62826bf03710200044e0bfc8bcbe5df1’); // Sys ID of the user
grMem.addQuery(‘group’, ‘477a05d153013010b846ddeeff7b1225’); // Sys ID of the group
grMem.query();
if (grMem.next()) {
grMem.deleteRecord();
}
User Interfaces and Key Concepts
ServiceNow offers different user interfaces, each with its own characteristics. Understanding these helps in designing user-friendly experiences.
User Interfaces in ServiceNow
Historically, ServiceNow has evolved through several UI frameworks: UI15, UI16, and the modern Next Experience UI. While the look and feel change, the underlying scripting capabilities often remain consistent, though specific syntax or best practices might adapt.
Web Services User
A web services user is a special type of user account. It’s designed to allow third-party applications to connect to ServiceNow and interact with its data or functionality programmatically, typically via APIs. Crucially, a web services user cannot log in to the ServiceNow instance as a regular user through the standard user interface.
Accessing User Information: Client vs. Server Side
Retrieving information about the currently logged-in user is a frequent requirement. The method differs depending on whether you’re scripting on the client or server.
- Client-Side: Use the
g_userobject. For example, to get the user’s sys_id:g_user.userID. - Server-Side: Use the
gsobject. For example, to get the user’s sys_id:gs.getUserID().
Checking Group Membership
A common task is to verify if the current user belongs to a specific group. This is easily done on the server-side:
Security Admin Role
When dealing with access control lists (ACLs) and security configurations, the security_admin role is paramount. You need this role to create, modify, or delete ACLs.
Impersonation: A Developer’s Best Friend
Impersonation is the ability to log in as another user. This is an indispensable tool for testing permissions, roles, and user-specific configurations. It allows you to experience ServiceNow exactly as another user would, ensuring your scripts and configurations behave as expected.
User Preferences
Users can personalize their ServiceNow experience by adjusting various settings in their User Preferences. These preferences are specific to the individual user and do not affect other users globally. This empowers users to tailor their interface and workflow to their liking.
Understanding Incident, Problem, and Change Management
These three modules are central to IT Service Management (ITSM) and are often intertwined.
Incident Management
An incident is defined as any event that interrupts or reduces the quality of a service. When an employee’s work is suddenly disrupted because something isn’t working, they create an incident to get support. The goal is to restore normal service operation as quickly as possible.
Problem Management
A problem is the underlying cause of one or more incidents. If the same issue (incident) occurs repeatedly for a single user, or if similar incidents affect multiple users simultaneously, it’s flagged as a problem. Problem management aims to identify the root cause and implement a permanent fix, preventing future incidents.
- Relationship: If a recurring issue affects multiple users, you might create a “parent” incident that acts as a focal point, with all related incidents linked as “child” incidents. Closing the parent often triggers the closure of children.
Change Management
Change management deals with the controlled modification of IT infrastructure or services. When a support engineer or IT team identifies that a change to a system (e.g., a software update, configuration adjustment) is needed to resolve a problem or improve a service, a change request is initiated.
Interrelationships and Workflows
- Incident to Problem: Yes, you can create a problem record from an incident if the issue is identified as recurring.
- Incident to Change Request: Yes, if resolving an incident requires a modification to the IT environment, a change request can be generated from the incident.
Creating Records via Script
Just like users and groups, incidents, problems, and change requests can be created programmatically:
var grIncident = new GlideRecord(‘incident’);
grIncident.initialize();
grIncident.caller_id = ‘86826bf03710200044e0bfc8bcbe5d94’; // Sys ID of the caller
grIncident.category = ‘inquiry’;
grIncident.subcategory = ‘antivirus’;
grIncident.cmdb_ci = ‘affd3c8437201000deeabfc8bcbe5dc3’; // Sys ID of the Configuration Item
grIncident.short_description = ‘Test record using script’;
grIncident.description = ‘Test record using script’;
grIncident.assignment_group = ‘a715cd759f2002002920bde8132e7018’; // Sys ID of the assignment group
grIncident.insert();
// Creating a Problem
var grProblem = new GlideRecord(‘problem’);
grProblem.initialize();
grProblem.caller_id = ‘86826bf03710200044e0bfc8bcbe5d94’;
grProblem.category = ‘inquiry’;
grProblem.subcategory = ‘antivirus’;
grProblem.cmdb_ci = ‘affd3c8437201000deeabfc8be5dc3’;
grProblem.short_description = ‘Test record using script’;
grProblem.description = ‘Test record using script’;
grProblem.assignment_group = ‘a715cd759f2002002920bde8132e7018’;
grProblem.insert();
// Creating a Change Request
var grChange = new GlideRecord(‘change_request’);
grChange.initialize();
grChange.category = ‘inquiry’;
grChange.subcategory = ‘antivirus’;
grChange.cmdb_ci = ‘affd3c8437201000deeabfc8bcbe5dc3’;
grChange.short_description = ‘Test record using script’;
grChange.description = ‘Test record using script’;
grChange.assignment_group = ‘a715cd759f2002002920bde8132e7018’;
grChange.insert();
Automating Workflows with Business Rules
Business rules are server-side scripts that run when a record is displayed, inserted, updated, or deleted. They are crucial for automating complex workflows and enforcing business logic.
Closing Child Incidents When Parent Closes
A common automation is to ensure that when a parent incident is closed, all its associated child incidents are also closed. This can be achieved with an ‘after’ business rule.
// Table: Incident
// When: After
// Update: true
// Condition: current.state.changesTo(7) // Assuming 7 is the state for ‘Closed’
if (current.state == 7 && current.parent == ”) { // Check if it’s a parent and being closed
var grChild = new GlideRecord(‘incident’);
grChild.addQuery(‘parent’, current.sys_id);
grChild.query();
while (grChild.next()) {
grChild.state = 7; // Set the state to Closed
grChild.update(); // Update the child incident
}
}
Preventing Closure of Incidents with Open Tasks
You might want to prevent an incident from being closed if there are still open incident tasks associated with it. This logic is best implemented as an ‘before’ business rule.
// Table: Incident
// When: Before
// Insert: false
// Update: true
// Condition: current.state.changesTo(3) // Assuming 3 is the state for ‘Closed’
var grTask = new GlideRecord(‘incident_task’);
grTask.addQuery(‘incident’, current.sys_id);
grTask.addQuery(‘state’, ‘!=’, 3); // Assuming 3 is the state value for ‘Closed’
grTask.query();
if (grTask.hasNext()) {
gs.addErrorMessage(‘Cannot close the incident because there are open tasks.’);
current.setAbortAction(true); // Prevents the update/closure
}
This logic can be extended similarly for Problem and Change Request records by querying their respective task tables (e.g., problem_task, change_task).
Closing Incidents When a Problem is Closed
When a problem is resolved and closed, it’s often desirable to close all associated incidents that were created due to this problem.
// Table: Problem
// When: After
// Update: true
// Condition: current.state.changesTo(7) // Assuming 7 is the state for ‘Closed’
if (current.state == 7) { // Check if the problem is being closed
var grIncident = new GlideRecord(‘incident’);
grIncident.addQuery(‘problem_id’, current.sys_id); // Link to the problem record
grIncident.addQuery(‘state’, ‘!=’, 7); // Assuming 7 is the state value for ‘Closed’
grIncident.query();
while (grIncident.next()) {
grIncident.state = 7; // Set the state to Closed
grIncident.update(); // Update the incident
}
}
Understanding Table Relationships and Structures
ServiceNow’s data model is built on tables. Understanding how tables relate and how they are structured is key to effective development.
Out-of-the-Box (OOB) Tables
Out-of-the-box tables are those provided by ServiceNow and typically do not start with x_ (custom applications) or u_ (legacy custom tables). Examples include incident, problem, and change_request.
Base Tables
Base tables are foundational tables that are not extended by any other tables but are extended by many. They serve as common repositories for data. Examples include:
task: A base table for many record types that involve work, like incidents, problems, and changes.cmdb_ci: The base table for Configuration Items in the Configuration Management Database (CMDB).
Task Tables
Task tables are tables that extend the task base table. They inherit common fields and functionalities from the task table.
- Examples:
incident,problem,change_request,sc_task(Service Catalog Task).
Table Creation and Access Controls (ACLs)
When you create a new table in ServiceNow, by default, four Access Control Lists (ACLs) are automatically generated if the checkbox to create ACLs is enabled. These provide basic Create, Read, Update, and Delete (CRUD) permissions.
Number Fields (e.g., Incident Number)
Fields like incident number are special. They are typically created as auto-number fields. When defining a table or field, you can configure an auto-number specification, defining a prefix (e.g., INC) and the number of digits for the sequence.
Extending Tables
When you extend a table (e.g., creating the incident table from the task table), the child table inherits fields from the parent. Crucially, the system fields (like sys_created_on, sys_updated_on) are not duplicated in the child table; they reside in the parent. A special field called class is added to the parent table to identify the specific child record type.
Common Field Types
ServiceNow supports a wide array of field types to capture different kinds of data. Here are some common ones:
- Reference
- String
- List
- Choice
- Date/Time
- Date
- Boolean
- Integer
- Journal
- Attachment
Temporary vs. Normal Tables
ServiceNow differentiates between temporary and normal tables:
- Temporary Tables: Designed for short-term data storage. They typically extend the
import_set_rowtable and retain data for a limited period (e.g., 7 days) before being purged. They are often used for staging data during import processes. - Normal Tables: Store data permanently until explicitly deleted.
You can increase the retention period for temporary tables using archive rules.
Remote Tables
Remote tables allow you to access live data from external data sources directly within ServiceNow, without needing to import and store it locally. This is in contrast to normal tables, which store data physically within the ServiceNow instance.
Table Relationships
Understanding how tables relate is vital for building complex applications:
- One-to-Many: A common scenario. Example: A single User can be associated with multiple Incidents. The relationship is defined on the “many” side (Incident table has a reference to the User table).
- Many-to-Many: An incident might be assigned to multiple groups, and a group might have multiple incidents assigned to them. This usually requires an intermediate “join” table (e.g.,
sys_user_group.listshows groups, and you can see members, but linking incidents to groups often involves other mechanisms or specific related lists). A classic many-to-many is where a user can be in multiple groups, and a group can have multiple users (sys_user_grmember).
Ways to Create Records
Records can be created in ServiceNow tables through various methods:
- Record Producer: User-friendly forms that create records.
- Email: Inbound email actions can create records.
- GlideRecord: Server-side scripting for programmatic creation.
- Forms: Direct user input on the form view.
- Excel Sheet: Data import using tools like Import Sets.
- External Systems: Via integrations using REST APIs or other web services.
Making Fields Mandatory or Read-Only
You can control field behavior in several ways:
- Dictionary Properties: Directly on the field’s dictionary entry (e.g., making it mandatory).
- Dictionary Overrides: To change the behavior of a field from a parent table in a child table.
- UI Policies: Client-side scripts to dynamically change field properties based on conditions.
- Data Policies: Similar to UI Policies but can also operate server-side, enforcing data consistency.
- Client-Side Script (g_form): Using
g_form.setMandatory(true/false)org_form.setReadOnly(true/false)within client scripts.
Display Fields: A Single Source of Truth
A table can have only one field designated as a display field. This is typically a field that uniquely identifies the record and is used in reference fields to show a meaningful value. Having more than one display field would lead to confusion.
Storing Table Definitions
All table definitions in ServiceNow are themselves stored in a table: sys_db_object.
Setting Default Values
To pre-populate a field when a form is opened, you can set a default value in the field’s dictionary entry. This ensures that users start with a sensible value, reducing manual entry.
The ‘current’ Object
The current object is fundamental in server-side scripting. It represents the record that is currently being processed (displayed, inserted, updated, or deleted). You use it to get and set values on that specific record.
- Setting Field Values:
current.setValue('field_name', value);: Use this for most field types. For reference fields,valueshould be thesys_id.current.setDisplayValue('field_name', value);: Use this when you want to set a field’s display value (e.g., setting a user’s name instead of their sys_id for a reference field).
Reference Qualifiers: Refining Reference Fields
Reference qualifiers are powerful tools for restricting the data users can select in reference and list fields. They ensure users pick relevant records, improving data accuracy.
Types of Reference Qualifiers
- Simple Reference Qualifier:
Description: The most straightforward type, using a fixed query condition to filter records. It’s like writing a basic `WHERE` clause for your query.
Example: To show only ‘Active’ users in a reference field for the User table, you’d set the condition to
active=true.Use Case: Filtering by a static attribute.
- Dynamic Reference Qualifier:
Description: This type leverages Dynamic Filter Options. These are pre-defined, reusable queries that can adapt based on runtime context, often referencing other fields on the form.
Example: Displaying only incidents assigned to the same assignment group as the current user.
Use Case: Context-aware filtering that doesn’t require custom scripting for every instance.
- Advanced Reference Qualifier (JavaScript Reference Qualifier):
Description: This is the most flexible type, allowing you to write custom JavaScript code directly in the reference qualifier field. This enables complex logic, computations, and dynamic filtering based on multiple conditions and the current user’s context.
Example: Filtering incidents to show only those assigned to the current user’s assignment group AND with a priority less than 3. The script would look something like:
javascript: 'assignment_group=' + current.getValue('assignment_group') + '^priority<3';(Note: This example shows a simplified structure; actual JS can be more complex).Use Case: Highly customized filtering logic.
Difference Between Types:
- Simple vs. Dynamic: Simple is static; Dynamic uses pre-defined, adaptable filters.
- Dynamic vs. Advanced: Dynamic uses pre-configured options; Advanced allows for custom JavaScript logic.
- Simple vs. Advanced: Simple uses basic conditions; Advanced uses complex JavaScript for maximum flexibility.
Dependent Fields and Calculated Values
Dependent Values
Dependent values are used to create cascaded dropdowns. When a user selects a value in one field (the parent), the choices available in another field (the dependent) are filtered accordingly.
Example: If the parent field is "Category" (e.g., Hardware, Software) and the dependent field is "Subcategory," selecting "Hardware" in Category would only show subcategories like "Laptop," "Desktop," etc., while selecting "Software" would show "Operating System," "Application," etc.
Configuration: This is set up in the dictionary entry of the dependent field by linking it to the parent field using the 'Dependent Field' attribute.
Calculated Values
A calculated value is a field whose value is automatically determined based on a formula or expression involving other fields. This is configured in the field's dictionary entry by selecting 'Calculated' as the type and providing a calculation script (often using the current object).
Example: A "Total Cost" field might be calculated by multiplying "Quantity" and "Unit Price."
Attributes and Dictionary Overrides
Attributes
Attributes are directives applied to fields (in their dictionary entries) to alter their behavior or appearance. They are a concise way to modify field functionality without writing extensive scripts.
Examples:
no_email: Prevents the field from being included in email notifications.no_attachment: Disables attachments for this field.tree_picker: Displays a field as a hierarchical tree view.mandatory: Makes a field mandatory (though this is also a dictionary property).
Enabling/Disabling Attachments
You can enable or disable the attachment icon on a form by using attributes on the collection field (the entry in sys_db_object that represents the table itself) in the dictionary. Adding the no_attachment attribute to the collection entry will disable attachments for all records of that table.
Dictionary Overrides
Dictionary overrides are used when you want a field in a child table to behave differently from the same field in its parent table. For instance, if the 'Priority' field in the base 'Task' table has a default value of 4, you could use a dictionary override on the 'Incident' table to change its default value to 5.
Properties that can be overridden: Almost any property defined in the field's dictionary entry, including Default value, Read only, Mandatory, Display, Max length, etc.
UI Policies and Data Policies: Controlling Form Behavior
These are essential tools for creating dynamic and user-friendly forms.
Application Menus and Modules
Application menus are top-level navigation items in the ServiceNow navigator. Modules are sub-items within application menus. They are used to make forms and lists accessible to end-users.
Process Flow
Process flow visually indicates the current stage of a record within a workflow. It helps users understand where they are in a process and what steps are next.
Data Lookups
Data lookup rules are a mechanism to automatically populate field values based on the values of other fields on the form. They are configured separately and can streamline data entry.
UI Policies
UI Policies are client-side scripts that dynamically control form elements (making fields mandatory, read-only, visible/hidden, setting default values) based on defined conditions. They are a low-code alternative to client scripts for many common scenarios.
- Global Checkbox: When checked, the UI Policy applies to all views. If unchecked, you specify the view(s) it should apply to.
- Reverse if False: If checked, the actions defined in the UI Policy are reversed when the condition is no longer met. For example, if a field was made mandatory when the condition was true, it becomes optional again when the condition is false.
- On Load Checkbox: If checked, the UI Policy executes when the form initially loads. If unchecked, it only runs when specific field changes trigger it.
- Inherit Checkbox: If checked, the UI Policy will also apply to child tables that extend the table on which the UI Policy is defined.
- Scripting in UI Policies: Yes, you can run scripts within UI Policies by enabling the 'Run scripts' checkbox in the UI Policy Action. This allows for more complex client-side manipulations.
Converting UI Policies to Data Policies
You can convert a UI Policy to a Data Policy. This is useful because Data Policies can operate on both the client and server, ensuring data consistency regardless of how the record is accessed.
When UI Policies Cannot Be Converted to Data Policies
There are specific scenarios where a direct conversion isn't feasible:
- When controlling data visibility (making fields visible/hidden). Data Policies primarily enforce mandatory/read-only, not visibility.
- When controlling views.
- When controlling related lists.
- When the UI Policy heavily relies on client-specific scripting for complex interactions that don't translate directly to server-side data logic.
Data Policies
Data Policies are similar to UI Policies but can operate on both the client and server side. They are used to enforce data consistency by making fields mandatory or read-only based on conditions, regardless of the user interface or data source. This makes them powerful for maintaining data integrity across the platform.
By understanding these different types of client scripts and related ServiceNow features, you can build more robust, efficient, and user-friendly applications. Happy scripting!