Mastering ServiceNow Incident Creation: A Technical Deep Dive with Scripting Best Practices
In the dynamic world of IT service management, the ability to efficiently create and manage incidents is paramount. ServiceNow, a leading platform for digital workflow, offers robust capabilities for handling these critical events. While the user interface is intuitive, understanding how to automate incident creation through scripting opens up a new realm of possibilities for streamlining operations and improving response times. This article will take you on a comprehensive journey into the heart of ServiceNow incident creation scripting, exploring the underlying concepts, practical examples, and best practices, all tailored for the latest Washington DC release.
Having worked with ServiceNow across various versions, from Rome all the way up to the current Washington DC, I’ve seen firsthand how these functionalities evolve. This guide is built on that experience, aiming to provide you with actionable insights that go beyond basic syntax, touching upon real-world scenarios and even interview-relevant knowledge.
Understanding the Foundation: What is an Incident?
Before we dive into scripting, let’s quickly recap what an incident signifies in the IT landscape. An incident is defined as a sudden interruption in the normal functioning of a service, or a reduction in the quality of that service. When an employee encounters something that’s suddenly stopped working, they rely on support engineers to resolve it, often by logging an incident.
This contrasts with a problem, which is the underlying cause of one or more incidents. If the same issue keeps cropping up, it’s likely a problem. In ServiceNow, a problem can have multiple incidents as its children. Similarly, a change request is initiated when a modification to the IT infrastructure is required, often in response to an incident or a proactive measure.
The relationship is cyclical: an incident might reveal a problem, leading to a change request. Understanding these relationships is key to effective ITSM, and scripting can help automate the linkages between these record types.
The Power of Scripting: Introducing GlideRecord
At the core of ServiceNow scripting for data manipulation lies the GlideRecord API. This powerful tool allows us to interact with almost any table in the ServiceNow instance, enabling us to create, read, update, and delete records. For incident creation, GlideRecord is our primary weapon of choice.
We’ll be focusing on the Washington DC version, but the principles and syntax remain largely consistent across recent releases like Rome, San Diego, Tokyo, Utah, and Vancouver. The underlying database structure and the GlideRecord API are stable, ensuring your scripts will be future-proof to a great extent.
Creating an Incident Record with GlideRecord
Let’s get straight to the most fundamental task: creating an incident record using a script. This is often triggered by various events – perhaps an automated system alert, an integration with a monitoring tool, or even a custom UI action on another form.
Here’s a basic script to create an incident. Imagine you’ve received an alert from a monitoring system indicating a critical server failure. You want to automatically create an incident for the IT support team.
// Script to create a new incident record
var grIncident = new GlideRecord('incident'); // Target the 'incident' table
grIncident.initialize(); // Prepare a new record object
// Setting essential fields
grIncident.setValue('caller_id', '86826bf03710200044e05d94'); // Sys ID of the user reporting the issue
grIncident.setValue('category', 'inquiry'); // e.g., 'hardware', 'software', 'network'
grIncident.setValue('subcategory', 'antivirus'); // e.g., 'printer', 'laptop', 'email'
grIncident.setValue('cmdb_ci', 'affd3c8437201000deeabfc8bcbe5dc3'); // Sys ID of the affected Configuration Item
grIncident.setValue('short_description', 'Critical server failure detected - Server XYZ'); // A concise summary of the issue
grIncident.setValue('description', 'Monitoring alert indicates Server XYZ is unresponsive. Please investigate immediately.'); // Detailed description of the problem
grIncident.setValue('assignment_group', 'a715cd759f2002002920bde8132e7018'); // Sys ID of the assignment group responsible for resolution
// Insert the new record into the database
var incidentSysId = grIncident.insert();
if (incidentSysId) {
gs.log('Incident created successfully: ' + incidentSysId);
// Optionally, you can perform further actions like setting state or adding work notes
var createdIncident = new GlideRecord('incident');
if (createdIncident.get(incidentSysId)) {
createdIncident.setValue('state', 1); // Example: Set state to 'New' (Sys ID might vary)
createdIncident.update();
gs.log('Incident ' + incidentSysId + ' state updated to New.');
}
} else {
gs.error('Failed to create incident.');
}
Breakdown:
new GlideRecord('incident');: This instantiates a GlideRecord object targeting the `incident` table.grIncident.initialize();: This prepares the GlideRecord object to create a new record.grIncident.setValue('field_name', value);: This is the standard way to set the value of a field. For reference fields (like `caller_id`, `cmdb_ci`, `assignment_group`), you’ll need to provide the Sys ID of the related record.grIncident.insert();: This is the crucial step that saves the new record to the `incident` table. It returns the Sys ID of the newly created record upon success.
Setting Field Values: setValue vs. setDisplayValue
When working with reference fields, it’s important to know how to set their values correctly. The setValue() method expects the Sys ID of the related record. However, you might sometimes have the display value (e.g., a user’s name or a CI’s name) instead of the Sys ID. In such cases, you can use setDisplayValue().
Best Practice: For automation scripts, it’s generally more robust to use Sys IDs directly. This avoids ambiguity and potential issues if multiple records share the same display value. If you only have the display value, you’d first need to query the target table to retrieve its Sys ID.
For example, to set the caller_id using their username (if you know it and can query for it):
var callerName = 'John Doe';
var userGr = new GlideRecord('sys_user');
if (userGr.get('name', callerName)) { // Assuming 'name' field holds the full name, or use 'first_name' and 'last_name'
grIncident.setValue('caller_id', userGr.getUniqueValue());
} else {
gs.warning('User ' + callerName + ' not found.');
// Handle the case where the user doesn't exist
}
Troubleshooting Common Incident Creation Issues
- Permissions: Ensure the user account running the script (or the system user if it’s a scheduled job or business rule) has write access to the `incident` table and read access to any tables you’re referencing (like `sys_user`, `cmdb_ci`, `sys_user_group`).
- Invalid Sys IDs: Double-check that all Sys IDs used for reference fields are correct. An invalid Sys ID will cause the `setValue` operation to fail or result in an incorrect association.
- Mandatory Fields: Ensure all mandatory fields on the `incident` form are being populated by the script. If not, the `insert()` operation will fail. You can check mandatory fields by right-clicking the form header, selecting “Configure” -> “Form Layout”, and then checking the “Mandatory” column.
- Data Types: Ensure the data type of the value you’re setting matches the field’s data type. For example, don’t try to set a date field with a string that’s not a valid date format.
Beyond Basic Creation: Linking Incidents to Problems and Changes
In a real-world ITSM scenario, incidents rarely exist in isolation. They are often related to broader problems or necessitate changes to the environment. ServiceNow provides mechanisms to link these records, and scripting can automate this process.
Creating a Problem from an Incident
If an incident points to a recurring issue, the next logical step is to create a problem record. This helps in root cause analysis and proactive problem management.
Scenario: A user reports a printer issue. If this issue is flagged as recurring or impacting multiple users, a support engineer might decide to create a problem record from it.
Here’s how you can script the creation of a problem record, linking it back to the incident:
// Script to create a problem record and link it to an incident
var currentIncidentSysId = 'a1b2c3d4e5f678901234567890abcdef'; // Sys ID of the current incident
var grProblem = new GlideRecord('problem');
grProblem.initialize();
// Set fields for the problem record
grProblem.setValue('problem_type', 'root_cause_analysis'); // Or other relevant problem types
grProblem.setValue('short_description', 'Recurring printer connectivity issues on floor 3');
grProblem.setValue('description', 'Multiple users reporting intermittent printer connectivity issues on floor 3. Investigating root cause.');
grProblem.setValue('assignment_group', 'e9f8d7c6b5a432109876543210fedcba'); // Assignment group for problem management
grProblem.setValue('contact_type', 'script'); // Or 'phone', 'email', etc.
grProblem.setValue('state', 1); // Set to 'New' or appropriate initial state
// Link the problem to the incident
grProblem.setValue('cause_of_incident', currentIncidentSysId); // Note: This field name might vary based on your instance configuration. A common way is to set the parent incident directly if the problem table has a reference to the incident table.
var problemSysId = grProblem.insert();
if (problemSysId) {
gs.log('Problem created successfully: ' + problemSysId);
// Update the original incident to link to the new problem
var grIncidentToUpdate = new GlideRecord('incident');
if (grIncidentToUpdate.get(currentIncidentSysId)) {
grIncidentToUpdate.setValue('problem_id', problemSysId); // Link incident to the problem
grIncidentToUpdate.update();
gs.log('Incident ' + currentIncidentSysId + ' linked to problem ' + problemSysId);
}
} else {
gs.error('Failed to create problem record.');
}
Important Note: The field name used to link an incident to a problem can vary. In many instances, the problem_id field exists on the incident table to reference the parent problem. Ensure you are using the correct field name for your instance.
Creating a Change Request from an Incident
When an incident is resolved, and it’s determined that a permanent fix requires a change to the underlying system, a change request is initiated.
Scenario: A software bug is causing frequent application crashes (incidents). The development team identifies that a code deployment is needed to fix the bug. A change request is created to manage this deployment.
Scripting can automate the creation of a change request:
// Script to create a change request and link it to an incident
var currentIncidentSysId = 'a1b2c3d4e5f678901234567890abcdef'; // Sys ID of the current incident
var grChange = new GlideRecord('change_request');
grChange.initialize();
// Set fields for the change request
grChange.setValue('category', 'software'); // e.g., 'hardware', 'software', 'network'
grChange.setValue('subcategory', 'patch'); // e.g., 'upgrade', 'deployment', 'fix'
grChange.setValue('short_description', 'Deploy patch to fix application crash bug');
grChange.setValue('description', 'Deploying a patch to resolve intermittent application crashes reported in INC0012345.');
grChange.setValue('assignment_group', 'abcdef1234567890fedcba0987654321'); // Assignment group for change management
grChange.setValue('cmdb_ci', 'affd3c8437201000deeabfc8bcbe5dc3'); // Affected Configuration Item
// Link the change request to the incident
grChange.setValue('parent_incident', currentIncidentSysId); // Field to link to the incident
var changeSysId = grChange.insert();
if (changeSysId) {
gs.log('Change request created successfully: ' + changeSysId);
// Update the original incident to link to the new change request
var grIncidentToUpdate = new GlideRecord('incident');
if (grIncidentToUpdate.get(currentIncidentSysId)) {
grIncidentToUpdate.setValue('business_service', 'your_business_service_sys_id'); // Example: Link to a business service if relevant
grIncidentToUpdate.setValue('change_request', changeSysId); // Link incident to the change request
grIncidentToUpdate.update();
gs.log('Incident ' + currentIncidentSysId + ' linked to change request ' + changeSysId);
}
} else {
gs.error('Failed to create change request.');
}
Note: Similar to the problem link, the field name for linking an incident to a change request (`parent_incident` or `change_request` on the incident table) might vary.
User and Group Management: The Backbone of Permissions
Creating incidents often involves assigning them to specific groups or users. Managing users and groups, and their associated permissions (roles), is a fundamental aspect of ServiceNow administration. Scripting can be instrumental in automating these processes, especially during onboarding or offboarding scenarios.
User and Group Tables
- User Table: The `sys_user` table stores all user records.
- Group Table: The `sys_user_group` table stores all group records.
- Group Member Table: The `sys_user_grmember` table links users to groups.
- User Role Table: The `sys_user_has_role` table links users to roles.
- Group Role Table: The `sys_group_has_role` table links groups to roles.
Creating Users and Groups with Scripts
Creating a User:
var userGr = new GlideRecord('sys_user');
userGr.initialize();
userGr.setValue('username', 'jdoe');
userGr.setValue('first_name', 'John');
userGr.setValue('last_name', 'Doe');
userGr.setValue('email', 'jdoe@example.com');
userGr.setValue('active', true); // Ensure the user is active
var userSysId = userGr.insert();
gs.log('User created with Sys ID: ' + userSysId);
Creating a Group:
var newGr = new GlideRecord('sys_user_group');
newGr.initialize();
newGr.setValue('name', 'IT Support - Tier 1');
newGr.setValue('manager', '62826bf03710200044e0bfc8bcbe5df1'); // Sys ID of the manager
newGr.setValue('email', 'itsupporttier1@example.com');
newGr.setValue('description', 'Handles initial IT support requests.');
var groupSysId = newGr.insert();
gs.log('Group created with Sys ID: ' + groupSysId);
Managing Permissions (Roles)
Best Practice: As noted in the reference, the best practice for managing permissions is through groups. When an employee leaves the organization, simply removing them from the relevant groups automatically revokes their permissions. This is far more efficient and less error-prone than managing roles individually on each user.
Adding a Role to a User:
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 (e.g., 'itil')
userRole.insert();
gs.log('Role added to user.');
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 (e.g., 'itil')
grpRole.insert();
gs.log('Role added to group.');
Adding and Removing Group Members
Automating user-to-group assignments is crucial for role management.
Adding a Group Member:
var grMem = new GlideRecord('sys_user_grmember');
grMem.initialize(); // Good practice to initialize even when setting values directly
grMem.setValue('user', '62826bf03710200044e0bfc8bcbe5df1'); // Sys ID of the user
grMem.setValue('group', '477a05d153013010b846ddeeff7b1225'); // Sys ID of the group
grMem.insert();
gs.log('User added to group.');
Removing a Group Member:
var grMem = new GlideRecord('sys_user_grmember');
grMem.addQuery('user', '62826bf03710200044e0bfc8bcbe5df1'); // User to remove
grMem.addQuery('group', '477a05d153013010b846ddeeff7b1225'); // Group to remove from
grMem.query();
if (grMem.next()) {
grMem.deleteRecord(); // Delete the membership record
gs.log('User removed from group.');
} else {
gs.warning('User not found in the specified group.');
}
Advanced Incident Management Automation
ServiceNow’s power lies not just in creating records but also in automating workflows based on record states and relationships. Business Rules are perfect for implementing such logic.
Logic for Auto-Closing Child Incidents
When a parent incident is closed, it’s often desirable to automatically close its associated child incidents. This ensures consistency and prevents orphaned open tickets.
Implementation: This is best achieved with an After Business Rule on the incident table.
// Business Rule: Auto-close child incidents when parent is closed
// Table: Incident
// When: After
// Insert: false
// Update: true
// Delete: false
// Condition: current.state.changesTo(7) && current.parent == ''
if (current.state == 7 && current.parent == '') { // Check if state is Closed (assuming 7 is 'Closed') and it's a parent incident
var grChild = new GlideRecord('incident');
grChild.addQuery('parent', current.sys_id); // Find incidents where 'parent' field matches the current incident's sys_id
grChild.query();
while (grChild.next()) {
grChild.setValue('state', 7); // Set the state to Closed
grChild.update(); // Update the child incident
gs.log('Child incident ' + grChild.number + ' closed automatically.');
}
}
Troubleshooting this Rule:
- State Value: Ensure `7` correctly represents the ‘Closed’ state in your instance’s `incident` table. You can verify this by inspecting the dictionary entry for the `state` field.
- Parent Field: The condition `current.parent == ”` ensures this logic only runs for top-level incidents (those that are parents themselves, not children).
- Script Errors: Check the System Logs (`System Logs > System Log > All`) for any errors if the child incidents are not closing.
Preventing Incident Closure with Open Tasks
To ensure a clean closure, you might want to prevent an incident from being closed if any associated incident tasks are still open.
Implementation: This requires a Before Business Rule on the incident table.
// Business Rule: Prevent incident closure if tasks are open
// Table: Incident
// When: Before
// Insert: false
// Update: true
// Delete: false
// Condition: current.state.changesTo(3) // Assuming 3 is the state value for 'Closed'
var grTask = new GlideRecord('incident_task');
grTask.addQuery('incident', current.sys_id); // Find incident tasks related to this incident
grTask.addQuery('state', '!=', 3); // Exclude tasks that are already Closed (assuming 3 is 'Closed')
grTask.query();
if (grTask.hasNext()) {
gs.addErrorMessage('Cannot close the incident because there are open incident tasks. Please resolve all tasks first.');
current.setAbortAction(true); // Prevent the update operation from completing
}
Troubleshooting this Rule:
- State Values: Verify the state values for ‘Closed’ on both the `incident` table and the `incident_task` table.
- `setAbortAction(true)`: This is critical. It stops the incident from being saved in the ‘Closed’ state if the condition is met.
- `gs.addErrorMessage()`: This provides user-friendly feedback explaining why the action was aborted.
This same logic can be adapted for problem and change_request tables by targeting their respective task tables (e.g., `problem_task`, `change_task`).
Auto-Closing Incidents When a Problem is Closed
Conversely, closing a problem often implies that its underlying incidents should also be addressed and closed.
Implementation: An After Business Rule on the problem table.
// Business Rule: Auto-close associated incidents when problem is closed
// Table: Problem
// When: After
// Insert: false
// Update: true
// Delete: false
// Condition: current.state.changesTo(7) // Assuming 7 is 'Closed' for problems
if (current.state == 7) { // Check if the problem state is now Closed
var grIncident = new GlideRecord('incident');
grIncident.addQuery('problem_id', current.sys_id); // Find incidents linked to this problem
grIncident.addQuery('state', '!=', 7); // Ensure we only update incidents that are not already closed
grIncident.query();
while (grIncident.next()) {
grIncident.setValue('state', 7); // Set the incident state to Closed
grIncident.update(); // Update the incident
gs.log('Incident ' + grIncident.number + ' closed automatically due to Problem closure.');
}
}
How to Create Records in ServiceNow Tables: A Quick Overview
You’ve seen GlideRecord in action, but it’s good to be aware of other methods for creating records:
- Form UI: The standard way users interact with ServiceNow.
- Record Producers: Catalogs items that create records in backend tables, often with a more guided user experience.
- Email: Inbound email actions can parse incoming emails to create or update records.
- External Systems: Integrations using REST APIs, SOAP, or other methods to push data into ServiceNow.
- Excel Import: For bulk data loading.
GlideRecord remains the go-to for server-side scripting and automation within ServiceNow.
Interview Relevance: What Interviewers Look For
When discussing incident creation scripting in an interview, interviewers are often looking for:
- Understanding of GlideRecord: Proficiency in using
initialize(),setValue(),insert(),query(),next(), anddeleteRecord(). - Table Knowledge: Familiarity with common tables like
incident,sys_user,sys_user_group, and their relationships. - Best Practices: Emphasizing group-based permissions, using Sys IDs for reference fields, and proper error handling.
- Business Rules: Ability to explain and implement server-side logic for automation (e.g., `before`, `after` rules, conditions, `setAbortAction()`).
- Problem and Change Management Integration: Understanding how incidents tie into the broader ITSM processes and how scripting can facilitate these connections.
- Troubleshooting Skills: Demonstrating an awareness of common issues and how to debug them (e.g., checking logs, verifying state values).
Conclusion
Mastering incident creation scripting in ServiceNow is a valuable skill that empowers you to build more efficient, automated, and robust IT service management solutions. By leveraging the power of GlideRecord and understanding the nuances of ServiceNow’s architecture, you can move beyond manual processes and unlock new levels of productivity.
Whether you’re automating alerts into incidents, linking incidents to problems and changes, or managing user permissions programmatically, this guide has provided you with the foundational knowledge and practical examples to get started. Continue to explore, experiment, and refine your scripts, and you’ll find yourself becoming an indispensable asset to your ServiceNow team.