Skip to content
Skillv1.0.0

servicenow-expert

Expert in ServiceNow platform development, scripting, workflows, Service Portal, CMDB, ITSM modules, and integrations. Use when the user mentions ITSM, ITOM, workflow, automation, CMDB, or service por

by personamanagmentlayer(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from personamanagmentlayer/pcl (stdlib/domains/servicenow-expert/SKILL.md). Install upstream with npx skills add personamanagmentlayer/pcl --skill servicenow-expert. Copyright stays with the author.

ServiceNow Expert

Core Concepts

ServiceNow Platform

  • ITSM - IT Service Management (Incident, Problem, Change)
  • ITOM - IT Operations Management
  • ITBM - IT Business Management
  • CMDB - Configuration Management Database
  • Service Portal - User-facing portal interface
  • Flow Designer - Visual workflow automation

Development Components

  • Business Rules - Server-side scripts on table operations
  • Client Scripts - Client-side validation and logic
  • UI Policies - Dynamic form behavior
  • Script Includes - Reusable server-side code libraries
  • Scheduled Jobs - Automated background tasks
  • Transform Maps - Data import/integration mapping

Scripting APIs

  • GlideRecord - Database query and manipulation
  • GlideAjax - Asynchronous client-server communication
  • GlideSystem - System utilities (gs object)
  • GlideDateTime - Date and time operations
  • GlideUser - User information and permissions
  • RESTMessageV2 - External API integration

Implementation Examples

GlideRecord Query and Update

// Business Rule - Update related records
(function executeRule(current, previous /*null when async*/) {
  // Query for related incidents
  var gr = new GlideRecord('incident');
  gr.addQuery('caller_id', current.sys_id);
  gr.addQuery('state', 'IN', '1,2,3'); // New, In Progress, On Hold
  gr.query();

  var incidentCount = 0;
  var incidentNumbers = [];

  while (gr.next()) {
    // Update priority based on user's VIP status
    if (current.vip == true) {
      gr.priority = '1'; // Critical
      gr.update();
      incidentCount++;
      incidentNumbers.push(gr.number.toString());
    }
  }

  // Log activity
  if (incidentCount > 0) {
    gs.addInfoMessage(
      'Updated ' + incidentCount + ' incidents: ' + incidentNumbers.join(', ')
    );
    gs.info(
      'VIP status updated for user ' +
        current.sys_id +
        ', affected incidents: ' +
        incidentNumbers.join(', ')
    );
  }
})(current, previous);

Script Include with REST API Integration

var ExternalAPIIntegration = Class.create();
ExternalAPIIntegration.prototype = Object.extendsObject(AbstractAjaxProcessor, {
  // Call external API to get user data
  getUserDetails: function (userId) {
    try {
      var request = new sn_ws.RESTMessageV2();
      request.setEndpoint('https://api.example.com/users/' + userId);
      request.setHttpMethod('GET');
      request.setRequestHeader('Accept', 'application/json');
      request.setRequestHeader('Authorization', 'Bearer ' + this._getToken());

      var response = request.execute();
      var httpStatus = response.getStatusCode();

      if (httpStatus == 200) {
        var responseBody = response.getBody();
        var jsonResponse = JSON.parse(responseBody);
        return jsonResponse;
      } else {
        gs.error('API call failed with status: ' + httpStatus);
        return null;
      }
    } catch (ex) {
      gs.error('Exception in getUserDetails: ' + ex.message);
      return null;
    }
  },

  // Sync user from external system
  syncUser: function (userId) {
    var userData = this.getUserDetails(userId);

    if (userData) {
      var gr = new GlideRecord('sys_user');
      gr.addQuery('employee_number', userData.employeeId);
      gr.query();

      if (gr.next()) {
        gr.email = userData.email;
        gr.phone = userData.phone;
        gr.department = this._getDepartmentId(userData.department);
        gr.title = userData.jobTitle;
        gr.update();

        gs.info('User synced successfully: ' + gr.sys_id);
        return gr.sys_id.toString();
      } else {
        gs.warn('User not found in ServiceNow: ' + userData.employeeId);
        return null;
      }
    }

    return null;
  },

  _getToken: function () {
    // Retrieve from system property or credential store
    return gs.getProperty('external.api.token');
  },

  _getDepartmentId: function (deptName) {
    var gr = new GlideRecord('cmn_department');
    gr.addQuery('name', deptName);
    gr.query();

    if (gr.next()) {
      return gr.sys_id.toString();
    }
    return '';
  },

  type: 'ExternalAPIIntegration',
});

Client Script with GlideAjax

// Client Script - onChange
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
  if (isLoading || newValue === '') {
    return;
  }

  // Call server-side script to validate user
  var ga = new GlideAjax('UserValidationAjax');
  ga.addParam('sysparm_name', 'validateUser');
  ga.addParam('sysparm_user_id', newValue);

  ga.getXMLAnswer(function (answer) {
    var result = JSON.parse(answer);

    if (!result.valid) {
      g_form.showErrorBox('caller_id', result.message);
      g_form.clearValue('caller_id');
    } else {
      // Populate additional fields
      g_form.setValue('caller_phone', result.phone);
      g_form.setValue('caller_email', result.email);

      // Show info message
      g_form.addInfoMessage('User validated: ' + result.name);
    }
  });
}
// Script Include for GlideAjax
var UserValidationAjax = Class.create();
UserValidationAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
  validateUser: function () {
    var userId = this.getParameter('sysparm_user_id');
    var result = {
      valid: false,
      message: '',
    };

    var gr = new GlideRecord('sys_user');
    if (gr.get(userId)) {
      if (!gr.active) {
        result.message = 'User is inactive';
      } else if (gr.locked_out) {
        result.message = 'User account is locked';
      } else {
        result.valid = true;
        result.name = gr.name.toString();
        result.phone = gr.phone.toString();
        result.email = gr.email.toString();
      }
    } else {
      result.message = 'User not found';
    }

    return JSON.stringify(result);
  },

  type: 'UserValidationAjax',
});

Service Portal Widget

// Server Script
(function () {
  /* Server-side script */

  data.incidents = [];

  var gr = new GlideRecord('incident');
  gr.addQuery('caller_id', gs.getUserID());
  gr.addQuery('active', true);
  gr.orderByDesc('sys_created_on');
  gr.setLimit(10);
  gr.query();

  while (gr.next()) {
    data.incidents.push({
      number: gr.getValue('number'),
      short_description: gr.getValue('short_description'),
      state: gr.getDisplayValue('state'),
      priority: gr.getDisplayValue('priority'),
      sys_id: gr.getValue('sys_id'),
      sys_created_on: gr.getValue('sys_created_on'),
    });
  }

  data.canCreateIncident = gs.hasRole('itil');
})();
<!-- HTML Template -->
<div class="panel panel-default">
  <div class="panel-heading">
    <h3 class="panel-title">My Incidents</h3>
  </div>
  <div class="panel-body">
    <div ng-if="data.incidents.length === 0" class="alert alert-info">
      No active incidents found
    </div>

    <table class="table table-striped" ng-if="data.incidents.length > 0">
      <thead>
        <tr>
          <th>Number</th>
          <th>Description</th>
          <th>State</th>
          <th>Priority</th>
          <th>Created</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat="incident in data.incidents">
          <td>
            <a href="?id=ticket&table=incident&sys_id={{incident.sys_id}}">
              {{incident.number}}
            </a>
          </td>
          <td>{{incident.short_description}}</td>
          <td>{{incident.state}}</td>
          <td>{{incident.priority}}</td>
          <td>{{incident.sys_created_on | date:'short'}}</td>
        </tr>
      </tbody>
    </table>

    <button
      ng-if="data.canCreateIncident"
      class="btn btn-primary"
      ng-click="c.createIncident()"
    >
      Create New Incident
    </button>
  </div>
</div>
// Client Controller
function($scope, spModal) {
    var c = this;

    c.createIncident = function() {
        spModal.open({
            title: 'Create Incident',
            widget: 'widget-sc-cat-item',
            widgetInput: {
                sys_id: 'incident_form_sys_id'
            }
        }).then(function(response) {
            // Refresh widget after creation
            c.server.refresh();
        });
    };
}

Flow Designer Action

// Script step in Flow Designer
(function execute(inputs, outputs) {
  var incidentId = inputs.incident_id;
  var gr = new GlideRecord('incident');

  if (gr.get(incidentId)) {
    // Calculate business hours since creation
    var schedule = new GlideSchedule();
    var scheduleId = gr.assignment_group.schedule.toString();

    if (scheduleId) {
      schedule.load(scheduleId);
    } else {
      // Default to 24x7
      schedule.load('08fcd0930a0a0b00079c3ee8a4efc9ba');
    }

    var createdDate = gr.sys_created_on.getGlideObject();
    var currentDate = new GlideDateTime();

    var duration = schedule.duration(createdDate, currentDate);
    var hours = duration.getDurationValue() / 3600; // Convert to hours

    outputs.business_hours = hours;
    outputs.is_sla_breach = hours > 24; // SLA is 24 hours

    // Update incident
    gr.u_business_hours_open = hours;
    gr.update();
  } else {
    outputs.business_hours = 0;
    outputs.is_sla_breach = false;
    gs.error('Incident not found: ' + incidentId);
  }
})(inputs, outputs);

Best Practices

Development Standards

  • Follow ServiceNow coding best practices
  • Use Script Includes for reusable code
  • Implement proper error handling
  • Add comments and documentation
  • Use meaningful variable names
  • Avoid global business rules when possible

Performance Optimization

  • Limit GlideRecord queries (use setLimit)
  • Use encoded queries for complex conditions
  • Avoid nested queries and loops
  • Implement caching where appropriate
  • Use async business rules for non-critical updates
  • Index frequently queried fields

Security Best Practices

  • Implement ACLs for data access control
  • Validate user input on client and server
  • Use GlideRecord instead of direct SQL
  • Follow principle of least privilege
  • Sanitize data before display
  • Use encrypted fields for sensitive data

Integration Patterns

  • Use REST API for modern integrations
  • Implement proper error handling and retry logic
  • Use credentials store for API keys
  • Log integration activities
  • Implement rate limiting
  • Use MID Server for on-premise connectivity

Anti-Patterns

Code Smells

  • Complex business rules with too much logic
  • Client scripts that make synchronous GlideAjax calls
  • Hardcoded sys_ids in scripts
  • Missing null checks on GlideRecord queries
  • Global variables without proper scoping
  • Direct DOM manipulation in Service Portal

Performance Issues

  • Queries without limits on large tables
  • Synchronous business rules that slow transactions
  • Missing indexes on custom fields
  • Recursive business rule triggers
  • Loading unnecessary related records
  • Heavy client scripts on form load

Design Issues

  • Tight coupling between components
  • No separation of concerns
  • Monolithic Script Includes
  • Duplicated code across multiple scripts
  • Poor error handling strategy
  • Missing logging and debugging info

Resources

Official Documentation

Learning Platforms

Tools & Resources

Community Resources

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/personamanagmentlayer-pcl-servicenow-expert/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

personamanagmentlayer-pcl-servicenow-expert.ocm.jsonjson
{
  "ocm": "1",
  "id": "personamanagmentlayer-pcl-servicenow-expert",
  "kind": "skill",
  "name": "servicenow-expert",
  "description": "Expert in ServiceNow platform development, scripting, workflows, Service Portal, CMDB, ITSM modules, and integrations. Use when the user mentions ITSM, ITOM, workflow, automation, CMDB, or service portal, or when the task involves ServiceNow Platform, Development Components, Scripting APIs, or GlideRecord Query and Update.",
  "publisher": "personamanagmentlayer",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "data_analysis"
    ],
    "tags": [
      "skill-md",
      "servicenow",
      "itsm",
      "itom",
      "workflow",
      "automation",
      "cmdb",
      "service-portal",
      "gliderecord",
      "business-rules"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Expert in ServiceNow platform development, scripting, workflows, Service Portal, CMDB, ITSM modules, and integrations. Use when the user mentions ITSM, ITOM, workflow, automation, CMDB, or service portal, or when the task involves ServiceNow Platform, Development Components, Scripting APIs, or GlideRecord Query and Update."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/personamanagmentlayer/pcl",
      "path": "stdlib/domains/servicenow-expert/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/personamanagmentlayer/pcl/blob/HEAD/stdlib/domains/servicenow-expert/SKILL.md",
      "key": "personamanagmentlayer/pcl/stdlib/domains/servicenow-expert/SKILL.md"
    },
    "allowed_tools": [
      "Read",
      "Write",
      "Bash",
      "WebSearch"
    ]
  },
  "instructions": "# ServiceNow Expert\n\n## Core Concepts\n\n### ServiceNow Platform\n\n- **ITSM** - IT Service Management (Incident, Problem, Change)\n- **ITOM** - IT Operations Management\n- **ITBM** - IT Business Management\n- **CMDB** - Configuration Management Database\n- **Service Portal** - User-facing portal interface\n- **Flow Designer** - Visual workflow automation\n\n### Development Components\n\n- **Business Rules** - Server-side scripts on table operations\n- **Client Scripts** - Client-side validation and logic\n- **UI Policies** - Dynamic form behavior\n- **Script Includes** - Reusable server-side code libraries\n-",
  "cost": {
    "context_tokens": 3226
  }
}

Fetch it by URL: GET /api/v1/registry/personamanagmentlayer-pcl-servicenow-expert/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.