Quantcast
Channel: Service-Now | John Andersen
Viewing all 82 articles
Browse latest View live

Getting a ServiceNow ECC Queue Response

$
0
0

Queue

I have added a couple of new functions to my “Integration Helper” script include that I wanted to quickly discuss.

The first function below allows you to take the sysID of an output record on the ECC Queue. The method will then poll the ecc queue every second for a resulting input record to be created (up to a maximum of either 25 seconds, or a time you specifically pass to the method). When the result comes back, the payload string will be returned.

The second function, which is used by the first, will grab the correct payload from the ecc queue. One interesting thing to note is that the payload will either be a string in the ecc_queue.payload field, or, if it is large enough, it will be contained in an attachment on the ecc queue record. This function will return the correct string whether it be in the payload field or stored as an attachment.

Please be aware that this function may take up memory temporarily if the payload attachment is exceedingly large.

The first function, getEccResponse, uses the second function, getEccPayload, to return the correct payload string.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
    /*
     * getEccResponse
   *
   * This method will take the sysID of an output record on the ECC queue
   * and wait up to a max number of MS for a corresponding "input"
   * response to be generated on the queue.
     *
     * PARAMS
     * outputSysId - The sys_id of the "output" record on the queue
     * waitMS - max number of miliseconds to to keep polling for the response.
     *
     * RETURNS
     * null - no response in within the max wait time;
     * Otherwise, we return the ECC Queue Payload string from the response record
     */

    getEccResponse: function(outputSysId,waitMS){
        if(!waitMS) {
            waitMS = 25000;
        }
        var start = new GlideDateTime;
       
       
        //Loop waiting for a record that is created in response to your query
        var resp = new GlideRecord("ecc_queue");
        resp.addQuery("response_to", outputSysId);
        resp.addQuery("queue", "input");
        do{
            resp.query();
            resp.next();
            gs.sleep(1000);
            if ( GlideDateTime.subtract(start, new GlideDateTime()).getNumericValue() > waitMS ) {
                return null;
            }
        } while(!resp.sys_id);
       
        //Found a response
        return this.getEccPayload(resp);
       
    },
   
   
   
    /*
     * getEccPayload
   *
   * Large payload bodies will create an attachment on the ECC Queue record.
   * This function will automatically determine if the response is an attachment
   * or if it is plain text within the payload field.  It will return the full
   * payload string regardless of whether it is contained within the field or in
   * an attachment.
     *
     * PARAMS
     * ecc - The GlideRecord of the ECC Queue record
     *
     * RETURNS
     * Full payload string
     *
     */

    getEccPayload: function(ecc){
       
        if(ecc.payload != "<see_attachment/>"){
            return ecc.payload;
        }
       
        var SysAttachment = Packages.com.glide.ui.SysAttachment;
        var sa = new SysAttachment();
        var payload = sa.get(gr, "payload");
       
        return payload;
    }

Username Token Profile for WS-Security in ServiceNow

$
0
0

wssecusertok

While ServiceNow does support the Signing of a SOAP Payload via WS-Security in the SOAP Consumer library, it does not provide out-of-the-box support for the UsernameToken profile of WS-Security.

The other day, a colleague of mine was creating an integration between ServiceNow and Workday, but the Workday instance was requiring WS-Security with the Username token profile. At first, we were worried that this would be an issue. However, after looking at the profile, I realized that there is an easy workaround for basic username profile WS-Security in ServiceNow.

In order to cover this workaround, let me first explain some of the very basics of the Username token as I understand it in WS-Security.

The username token is additional XML that is found in the SOAP Envelope Header. There are four main possible elements that I have seen most often. These are: Username, Password, Timestamp, and Nonce.

Username
This is just a plain text element that represents the username to be authenticated in the request.

Password
Typically this is just a plain text element that represents the password to the username. However, some web services will require this to be a digest hash using a shared secret hashed together with other information for security purposes (see the Oasis specification for more details)

Timestamp
This is a timestamp string in ISO-8601 format that gives the time of the request (you can generate this in ServiceNow by following the steps in my blog post on “Generating an ISO-8601 timestamp in ServiceNow“. The timestamp element may be optional.

Nonce
This is a unique string that will never be used again in a web service call. It depends on the web service whether this will be used, and how it will be used. Sometimes it is a hash, other times it is just a guid-type string. This element may be optional.

In the case of the Workday Authentication, the WS-Security only required the Username and Password elements. Therefore, the WS-Security string would need to look something like:

1
2
3
4
<wsse:UsernameToken>  
 <wsse:Username>MyWorkdayUser</wsse:Username>  
 <wsse:Password>MyPassword</wsse:Password>  
</wsse:UsernameToken>

In order to code this up, we added the following XML into the SOAP Envelope Header:

1
2
3
4
5
6
7
8
9
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:bsvc="urn:com.workday/bsvc">
<soapenv:Header>
  <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <wsse:UsernameToken wsu:Id="UsernameToken-3">
      <wsse:Username>${username}</wsse:Username>
      <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">${password}</wsse:Password>
    </wsse:UsernameToken>
  </wsse:Security>
</soapenv:Header>

We then were able to pass variable values in for the “${username}” and “${password}” macro variables in the request.

With this, we were able to make SOAP requests with the UsernameToken WS-Security profile.

Example of UI Macros and UI Pages in ServiceNow

$
0
0

uimacropageicon

The following is a quick example of how to leverage UI Macros in ServiceNow to be reusable blocks of content (whether it be text, javascript, css, or HTML) for UI Pages. Of course you can do something similar with CMS, but this tutorial is for UI Macros and Pages.

UI macros are modular, reusable components that can be used throughout the ServiceNow platform. They are like little “include” files, if you will, that can be inserted on pages, forms, etc. For more information on UI Macros, please visit the UI Macro Documentation.

To demonstrate how we can leverage a UI Macro inside of a UI page, let’s assume we want to have a standard Header and Footer on a set of UI Pages. We don’t want to copy the Header and Footer code and paste them in each UI page. This would be a maintenance nightmare. Instead, we will create a UI macro for the Header and one for the Footer. We will then include references to the macros inside of our UI Page.

Creating the Header

Browse to System UI > UI Macros in your navigation pane in ServiceNow, and create a new UI Macro.

Name: TestHeader
Active: checked
XML:

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<div style='width:100%; font-size: 2em; color: black; text-align: left; background-color: orange;'>
My Big Header
</div>
</j:jelly>

Click Update

Creating the Footer

Click the NEW button on the UI Macro list to create another macro.

Name: TestFooter
Active: checked
XML:

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<div style='width:100%; font-size: 0.7em; color: white; text-align: center; background-color: black;'>
My Little Footer (c) 2013 - http://www.john-james-andersen.com
</div>
</j:jelly>

Click Update

Create the UI Page

Browse to System UI > UI Pages

Click the NEW button on the UI Page list to create a new UI Page.

Name: TestPage
HTML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<g:macro_invoke macro="TestHeader" />
<table>
  <tr>
    <td style='width: 100px;'>Menu<br/>Option 1<br/>Option 2</td>
    <td>Now is the time for all good men to come to the aid of the party.  
        The quick brown fox jumps over the lazy dog.
        At the beginning of your upkeep, if you control permanents
        with names that include all twenty-six letters of the
        English alphabet, you win the game.</td>
  </tr>
</table>
<g:macro_invoke macro="TestFooter" />
</j:jelly>

Notice the tags inside the UI Page. They tell the page to query a UI Macro and insert the contents of that macro in its place. The attribute macro=”TestHeader” tells the UI page to query all UI Macros for a macro named, “TestHeader”. That is the macro that will be used.

If you were to test the UI page that leverages these two macros, your page would look something like the following:

uimacropage

Create your own REST-based ServiceNow Web Service

$
0
0

custometools

ServiceNow boasts a wide range of capabilities in their out-of-box SOAP and REST web services. There are times, however, where you need something that is totally custom, and not found out of the box. With SOAP, you can always leverage the “Scripted Web Services” feature of the product to create your own SOAP based web service within the platform. However, most people don’t know you can do something similar for REST based web services as well!

The place I like to go to in order to develop my own REST based web service, is to create my own Scripted Processor.

Types of Processors

There are two types of processors, Script based and Java based. Java based processors leverage Java code built in the platform. This is something that is core to the ServiceNow platform and not available for users to create on their own. Scripted processors will execute user-specified Javascript code.

Processors are accessed either by Path, or by URL parameter. If you create a Path processor, then it is accessed by a specific, static URL (eg. https://myinstance.service-now.com/my_scripted_processor.do). If you create a Parameter specific processor, you can leverage the processor any any standard ServiceNow page by adding a URL parameter to the URL (eg. https://myinstance.service-now.com/incident.do?MYPROCESSOR).

Global Variables and Functions

Every scripted processor has the following four global variables/objects that you can leverage:

  • g_request – This is the HTTP Request object. It contains information about the request itself.
  • g_response – This is the outgoing HTTP Response object that will be posted back to the client.
  • g_target – If you are using a Parameter-based processor, this is the table that the processor is acting on. This does not apply for Path-based processors
  • g_processor – This is the actual processor object.

For our example, of a custom REST based Web Service, we are going to leverage the g_request, g_response, and g_processor objects. The following are the methods that will be handy for us:

g_request.getMethod()
This returns a string value of the HTTP Method used in the call. REST-based systems will typically be one of four methods: GET, POST, PUT, DELETE.

g_request.getHeaderNames()
This will return a Java Enumerator on a list of HTTP Header Names that were sent with the request. This is helpful if you want to use any header information that is sent from the client.

g_request.getHeader({headerName})
Given a header name, this will return the value of that HTTP Request Header.

g_request.getParameterNames()
This will return a Java Enumerator on a list of the various URL Parameters used in the Request URI. You can leverage URL parameters that were submitted with the request by using this function.

g_request.getParameter({parameterName})
Given a parameter name, this will return the value of the URL Parameter used in the request.

g_request.getInputStream()
This function will return a Java InputStream that will stream the body content of the request to your script. You can use the GlideStringUtil.getStringFromStream({inputStream}) java API call to convert the stream into a string variable.

g_response.setHeader({headerName}, {headerValue})
This function on the g_response object will set a new Header name and value on the response. This is useful if you have header data that you need to provide back to the client that is calling your web service.

g_processor.writeOutput({outputString})
Use this method to set the body of the content that you will be returning to the client with the response. This will typically be XML or JSON data, but can be anything (text-based) you need it to be.

Creating a Sample Processor

We are going to take the information above to create a REST based web service that will expect a string that represents a person and the cars that they drive. Based on the Content-Type HTTP Header sent in the request, we will determine whether the string representing the person is a JSON string or an XML string.

We will then build a custom response for the client that called the web service, displaying all of the headers we received from them as well as any URL parameters. Then give them a message of what we are going to do with the data they provided. We will also let the client know that the message we are giving back to them is in plain text format by setting our response Content-Type HTTP Header appropriately.

The Processor

Name: SampleWebService1
Type: script
Active: true
Description: Demonstrate how to handle an inbound REST based request
Path: SampleWebService1
Script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
 * We could create logic around what to do if this request is
 * a GET, PUT, POST, or DELETE request.  To get that HTTP Method,
 * we use the getMethod() function on the request.
 * In this example, we just log it to a string variable
 */

var methodMsg = "Method string: "+g_request.getMethod()+"\n";

/*
 * We could iterate through all of the headers to make
 * intelligent decisions about how to handle this request,
 * but in this example, we will just write each header
 * and its value to a logging string
 */

var headerList = g_request.getHeaderNames();
var headerMsg = ""; //we're going to log header info here
while(headerList.hasMoreElements()){
    var header = headerList.nextElement();
    var value = g_request.getHeader(header);
    headerMsg += ("Header: ["+header+"] has a value of: "+value+"\n");
}

/*
 * We could iterate through all of the URL parameters to make
 * intelligent decisions about how to handle this request,
 * but in this example, we will just write each URL parameter
 * and its value to a logging string
 */

var urlParamList = g_request.getParameterNames();
var paramMsg = ""; //we're going to log parameter info here
while(urlParamList.hasMoreElements()){
    var param = urlParamList.nextElement();
    var value = g_request.getParameter(param);
    paramMsg += ("Parameter: ["+param+"] has a value of: "+value+"\n");
}

/*
 * Grab the input stream from the request and store the stream contents
 * into a variable, "sb" in this case, so that we can read it easily
 */

var inputStream = g_request.getInputStream();
var is = g_request.getInputStream();
var sb = GlideStringUtil.getStringFromStream(is);

var contentType = g_request.getHeader("Content-Type");
if( contentType == "application/xml" ){
    /*
     * The body is supposed to be in XML format, convert it to an object
     * using ServiceNow XML libraries
     */

    var helper = new XMLHelper(""+sb);
    var person = helper.toObject();
} else {
    /*
     * The body is not XML, so we are going to assume it is in JSON format.
     * Use ServiceNow libraries to covert the JSON string to an object
     */

    var parser = new JSONParser();
    var person = parser.parse(sb);
}


/*
 * Now we would normally process the request given the data posted to
 * us.  However, for this example, we are going to simply build out
 * a text response that is tailored to the information given to us
 */

var returnMessage = "";
returnMessage += "We received a Request from you with the following information:\n";
returnMessage += methodMsg;
returnMessage += "\nWITH INCOMING HEADERS\n";
returnMessage += headerMsg;
returnMessage += "\nWITH URL PARAMETERS OF\n";
returnMessage += paramMsg;
returnMessage += "\n\n";
returnMessage += "We will process the following vehicles for ";
returnMessage += person.first + " " + person.last + ":\n";
if( person.cars.car ){
  //XML case
    var listOfCars = person.cars.car;
} else {
  //JSON case
    var listOfCars = person.cars;
}
for(key in listOfCars){
    returnMessage += listOfCars[key].year + "-";
    returnMessage += listOfCars[key].make + "-";
    returnMessage += listOfCars[key].model + "\n";
}

/*
 * We can set headers in our response to the client.  In this case, we will
 * send a "Content-Type" header to tell the client
 * that our response is just plain text.  Normally we would respond
 * in JSON or XML format.  But, we will keep it simple.
 */

g_response.setHeader("Content-Type", "text/plain");

/*
 * If we want to send information back to the client, we can
 * do so through the writeOutput function on the processor
 */

g_processor.writeOutput(returnMessage);

Testing the Processor using JSON content

Using my favorite REST Client, I am going to post some test parameters and headers to my web service. I am going to make sure to set my Content-Type header to “application/json” to tell the processor that my data is coming in as JSON formatted data.

Postman

My client will get the following response from the web service:

Incoming Headers

Content-Encoding →gzip
Content-Length →870
Content-Type →text/plain
Date →Tue, 03 Sep 2013 17:30:08 GMT
Server →ServiceNow
X-TRANSACTION-TIME →0:00:00.018
X-TRANSACTION-TIME-MS →18

Body of response

We received a Request from you with the following information:
Method string: POST

WITH INCOMING HEADERS
Header: [host] has a value of: MINSTANCE.service-now.com
Header: [connection] has a value of: keep-alive
Header: [content-length] has a value of: 248
Header: [authorization] has a value of: Basic YWRtaW46YWRtaW4=
Header: [cache-control] has a value of: no-cache
Header: [origin] has a value of: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
Header: [user-agent] has a value of: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36
Header: [content-type] has a value of: application/json
Header: [accept] has a value of: */*
Header: [accept-encoding] has a value of: gzip,deflate,sdch
Header: [accept-language] has a value of: en-US,en;q=0.8
Header: [cookie] has a value of: tomato_menu_status=overview.asp; tomato_status_overview_refresh=3; tomato_menu_forward=basic.asp; atlassian.xsrf.token=BLX9-YBA9-J0XM-8QS5|6d54b8deee7f3fdd6744ae62c0f7a964f888996d|lout; JSESSIONID=8E09B5D54088B641DB27D243FB2E4086; glide_user="U0N2MjpiZTdiM2Q5YTg4MmZjMTAwZjhlNjNhZDc5NzE5YzA5NDo2ODE2Zjc5Y2MwYTgwMTY0MDFjNWEzM2JlMDRiZTQ0MQ=="; glide_user_session="U0N2MjpiZTdiM2Q5YTg4MmZjMTAwZjhlNjNhZDc5NzE5YzA5NDo2ODE2Zjc5Y2MwYTgwMTY0MDFjNWEzM2JlMDRiZTQ0MQ=="; glide_user_route=glide.e37cb7a788a9996b305ac28d6d4a9d8a

WITH URL PARAMETERS OF
Parameter: [MySecondParam] has a value of: IsNotAwesome
Parameter: [MyFirstParam] has a value of: IsAwesome


We will process the following vehicles for John Andersen:
1999-ford-F-150
2008-chevrolet-Suburban

Testing the Processor using XML content

Using my favorite REST Client, I am going to post some sample parameters and headers to my web service. I am going to make sure to set my Content-Type header to “application/xml” to tell the processor that my data is coming in as XML formatted data.

Postman-2

My client will get the following response from the web service:

Incoming Headers

Content-Encoding →gzip
Content-Length →864
Content-Type →text/plain
Date →Tue, 03 Sep 2013 18:29:32 GMT
Server →ServiceNow
X-TRANSACTION-TIME →0:00:00.056
X-TRANSACTION-TIME-MS →56

Body of response

We received a Request from you with the following information:
Method string: POST

WITH INCOMING HEADERS
Header: [host] has a value of: MYINSTANCE.service-now.com
Header: [connection] has a value of: keep-alive
Header: [content-length] has a value of: 284
Header: [authorization] has a value of: Basic YWRtaW46YWRtaW4=
Header: [cache-control] has a value of: no-cache
Header: [origin] has a value of: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
Header: [user-agent] has a value of: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36
Header: [content-type] has a value of: application/xml
Header: [accept] has a value of: */*
Header: [accept-encoding] has a value of: gzip,deflate,sdch
Header: [accept-language] has a value of: en-US,en;q=0.8
Header: [cookie] has a value of: tomato_menu_status=overview.asp; tomato_status_overview_refresh=3; tomato_menu_forward=basic.asp; atlassian.xsrf.token=BLX9-YBA9-J0XM-8QS5|6d54b8deee7f3fdd6744ae62c0f7a964f888996d|lout; JSESSIONID=8E09B5D54088B641DB27D243FB2E4086; glide_user="U0N2MjpiZTdiM2Q5YTg4MmZjMTAwZjhlNjNhZDc5NzE5YzA5NDo2ODE2Zjc5Y2MwYTgwMTY0MDFjNWEzM2JlMDRiZTQ0MQ=="; glide_user_session="U0N2MjpiZTdiM2Q5YTg4MmZjMTAwZjhlNjNhZDc5NzE5YzA5NDo2ODE2Zjc5Y2MwYTgwMTY0MDFjNWEzM2JlMDRiZTQ0MQ=="; glide_user_route=glide.e37cb7a788a9996b305ac28d6d4a9d8a

WITH URL PARAMETERS OF
Parameter: [MySecondParam] has a value of: IsNotAwesome
Parameter: [MyFirstParam] has a value of: IsAwesome


We will process the following vehicles for Amber Andersen:
2002-Honda-Rebel
2000-Toyota-Avalon

How to make a ServiceNow Processor Public

$
0
0

Processors, along with everything else in the ServiceNow product are protected by authentication. When a user comes to the processor in a browser, they will be asked to log in. If a script, or web service client tries to access the processor, it will be denied unless it presents a Basic Authentication header.

This is usually the desired case, however, there are times when you want to make a certain processors open, without the authentication requirement.

In order to do this, you must leverage the Public Pages list inside of ServiceNow to get a scripted path processor to be public.

The following video shows a quick example on how to make a path processor public.

How to make a ServiceNow Processor Public

Export data from ServiceNow to XML with Perl

$
0
0

export.pl

Quick Preface: Many of my friends and community members have written their own custom processors, or tools to give them powerful export capabilities from ServiceNow. Crossfuze’s Scheduled Data Extract, Jason Petty’s FTP Export tool, and others come to mind. However, the purpose of this article is to focus on using the Out-of-Box export interface that uses no other technology other than the HTTP Requestor (a Perl script, in this case).

The Basics of Chunking an Export

ServiceNow offers a number of out-of-box ways to export its data. However, other than the ODBC driver, all of the export mechanisms have record limits placed on them so as not to bring down the instance when exporting a large number of records from a table.

The XML Web Service, however, does have some capabilities that allow you to easily and reliably chunk the requests using paged queries. Using the wiki documentation on exporting large amount of data, you can get the general feel for how to leverage the XML web service processor to export the full contents of a table in a paged manner so as to use several smaller requests that don’t bring the instance to its knees.

Essentially, through a series of request parameters, you sort the data on a field in the table. In most cases this would be the sys_id field. You also give it a max number of records to return in a given request. Finally, you specify a beginning value to start with in each given request (eg. use the last value of the sorted field from the previous request made). Optionally, you can choose to have the data exported in “unload” format that shows both Display Values as well as sys_id values. You can also filter the data before exporting it so that you only bring in data that matches certain criteria.

Any REST based client should be able to export data in this manner as long as it can read the response and generate a new request based on the last record that was brought over.

In order to show you how this is done, I have created a Perl Script/Utility that allows you to quickly and easily export data from a ServiceNow table into a file on your file system.

Perl-based Utility

The perl utility does require that you have Perl installed with some of the core libraries. Additionally, you will need the following Perl libraries that are available via CPAN:

  • LWP::UserAgent
  • HTTP::Request
  • XML::XPath

The script will accept the following command line arguements:

  • Table – The name of the ServiceNow table. (Not the table label, but the actual name)
  • Base Instance URL – This is the full URL to access the ServiceNow instance (eg. https://MyInstance.service-now.com)
  • Username – A username for a user that has privleges to access the table and its data
  • Password – The password for the user
  • Page Size – How many records should be returned with each web request. There is no hard and fast rule for this, however, I like to keep it around 100 or 1000. Test to see what works best for you.
  • Show Display Values – YES: show the display values for records in addition to the sys_id; NO – return only sys_id’s for reference field data
  • Encoded Query (optional) – An encoded query that filters the data in case you only want to export qualified data.

Running the script as simply:

export.pl

will give you all of the parameters as well as some examples.

Here is the code. I tried to make a lot of comments so as to teach you what is going on under the covers:

Call a ServiceNow script asynchronously with ScheduleOnce API

$
0
0

hourglass

A lot of people don’t know that there is an easy way to call a script to run asynchronously (with the next available worker thread) within the current ServiceNow API set.

There are a couple of Script Includes in the product that allow you to do this. The easiest API is the “ScheduleOnce” class. This class inherits from the “Schedule” class. The schedule class lets you set the schedule for a script while the ScheduleOnce class tells the system to throw it on the job queue and execute it at the next available spot.

To leverage the ScheduleOnce class, simply instantiate it, set the “script” variable with your script, and then call the “schedule()” method.

1
2
3
var so = new ScheduleOnce();
so.script = "//Your script as a string goes here";
so.schedule();

Please keep in mind that you cannot pass objects into the asynchronous script. You must represent everything as a string when you set the script variable.

Example

SchedOnceBR

For example, let’s say we have a Script Include library called “AuditWebService”. This library sends a web service call to a third party auditing server. This server wants to be notified any time the priority changes on any incident in the system. Not only does it want the current value, but the previous value as well.

We don’t want this to hold up the user experience, so we want to make this an asynchronous event. However, we can’t use the “async” business rule setting because we need both the current and previous versions of the priority. “async” business rules can only have the “current” values, and even that is limited on some fields based on the timing.

In order to do this, we will leverage the ScheduleOnce class within a “Before” business rule. The “Before” business rule still gives us the current and previous values from the business rule instance. But the ScheduleOnce allows us to tell the system to send the data asynchronously rather than hold up the save action for the web service call to go out.

Your business rule might look like this:

Name: Log Priority Change to Audit Server
Table: Incident [incident]
When: before
Insert: checked
Update: checked
Condition: current.priority.changes()
Script:

1
2
3
4
5
6
7
8
9
10
11
12
//Instantiate the ScheduleOnce class object
var so = new ScheduleOnce();

//Set the script variable to run the Audit Script Include
so.script = "var audit = new AuditWebService();";
so.script += "audit.setRecord('"+current.number+"');";
so.script += "audit.setPreviousPriority('"+previous.priority+"');";
so.script += "audit.setNewPriority('"+current.priority+"');"
so.script += "audit.sendToWebService();";

//Schedule the script to run
so.schedule();

Creating Dependent Choice Lists in ServiceNow

$
0
0

DepChoice

A couple of weeks ago someone asked me for some clarification on how to create a drop-down box that has values that change depending on the selected value of another drop-down box.

For example, if we are on incident form, and select a category of Restaurants, we may want the subcategory select menu change to only show subcategories of the Restaurant category, rather than all subcategories available to the form.

Rather than type out instructions or refer them to the wiki, it was quicker just to do a rough little video that showed how you might create drop-down list with values that are dependent upon the selection of another drop down choice list.

Sorry this is not polished, but it was a quick explanation of a simple process.


Access Secure Data in MID Server Scripts

$
0
0

mid_server_-_Google_Search

In a post I created a while ago, I talked about passing parameters from a ServiceNow script to a MID Server script include via the ECC Queue. (see Javascript Probes and MID Server Script Includes)

This is typically a fine practice. However, if one of those parameters contains a password to a third party system, then that password will be in plain text format on the ECC Queue. Some people are OK with this since ECC Queue entries are limited to System Admins, etc, however others still do not feel comfortable having a password in plain text on the queue.

You can get around this problem in two ways: 1) Create a MID Server property and store the password there, or 2) Use RemoteGlideRecord from the MID Server Script include to query a system property on the fly.

MID Server Property Method

You can create MID Server properties in the ServiceNow instance by browsing to MID Server > Properties.

ServiceNow_Service_Automation

In this example, I created a MID Server Property called “john.test”, with a value of “andersen”.

ServiceNow_Service_Automation-2

Your MID Server Script Include can access a MID Server property but instantiating the “Packages.com.service_now.mid.service.Config” class and leveraging the “getProperty” function.

In the follow code snippet, I am going to get the value of my “john.test” MID Server Property:

1
2
3
config = Packages.com.service_now.mid.services.Config.get();
var test = config.getProperty("john.test");
ms.log("TEST: " + test);

When I execute this code in my MID Server Background Scripts module, I get the following results:

MID Server background script result:

*** Script: TEST: andersen

RemoteGlideRecord Process

The RemoteGlideRecord method leverages a MID Server library call by the name of “Packages.com.glide.communications.RemoteGlideRecord”. This method is similar to the “GlideRecord” API but instead of querying the database within an instance, it makes a SOAP Web Service call to an instance to get the data required for the GlideRecord call.

In order to leverage this, however, you need to set the authentication for the call. This can typically be done by the MID Server user, as long as that user has rights to access the data from the RemoteGlideRecord call. In this case, my MID Server user is the “admin” user, and I know that that user has rights to query the sys_properties table.

In the following example, I am using the RemoteGlideRecord call to query the sys_properties table for a property called: “glide.installation.name”.

1
2
3
4
5
6
7
8
9
10
config = Packages.com.service_now.mid.services.Config.get();
var user =    config.getProperty("mid.instance.username");
var password =config.getProperty("mid.instance.password");

var rgr = new Packages.com.glide.communications.RemoteGlideRecord("https://MYINSTANCE.service-now.com", "sys_properties");
rgr.setBasicAuth(user, password);
rgr.addQuery("name", "glide.installation.name");
rgr.query();
rgr.next();
ms.log("Glide Installation Name: " + rgr.getValue("value"));

I get the following result when I execute this script in my MID Server Background Scripts Module:

MID Server background script result:

*** Script: Glide Installation Name: Demo Server
Slow execution (141ms) of script: ad_hoc:null

Notice the “Slow Execution” warning I got. That is due to the fact that I made a SOAP web service call back to the instance during my script to get a system property value.

Pros and Cons

The MID Server Property method is nice because these properties get cached on the MID Server so that the script doesn’t have to make a SOAP call during the execution in order to get the sensitive data. However, this does require additional set up on your part to create the MID Server Property and maintain that record.

RemoteGlideRecord is flexible and can read any database table in the system that you have rights to access. This lets you query more that just system properties. Also, you don’t have to set anything special up on the ServiceNow instance, you just access data that is already there. However, I do not like the fact that RemoteGlideRecord has to make individual SOAP calls to the instance to get that data. This can slow your scripts down a little bit and it may have an impact on the instance. If you are just querying a password value, then it may not be much of an impact at all, but the risk still exists.

In summary, I prefer the MID Server Property method. It does require that I set up that property, but in the overall scheme of things, I like the fact that I don’t have to make additional web service calls during my script execution. Also, I have no guarantee that the MID Server user will have the correct roles required to do the RemoteGlideRecord call that I am performing.

Show External Websites in a Dialog From ServiceNow Lists

$
0
0

There are several good examples on blogs and the ServiceNow wiki of creating a popup-style dialog box to show form or list data from another ServiceNow form. I wanted to use those examples to create yet another scenario: From a ServiceNow list, right-click on a record and have an external website pop up as a dialog box and accept information from the list record that was selected.

In this example, users can browse incidents in their ServiceNow instance. In the list view, they can right-click an incident and choose an option to view related search results in Mozilla’s Open Directory Project (DMOZ.org). The action will take the terms from the “Short Description” field on the selected incident and show search results on those terms from DMOZ.

In order to to this, we are going to only really need to create two thing:

  • A UI Page that iframe’s the dmoz website
  • A UI Macro that launches the UI Page in a GlideDialogWindow

UI Page

Name: search_dmoz
HTML:

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
  <g:evaluate var="jvar_queryTerms"
   expression="RP.getWindowProperties().get('queryTerms')" />
  <iframe src='http://www.dmoz.org/search?q=${jvar_queryTerms}' width='700' height='300'>
    Please Enable iFrames</iframe>
</j:jelly>

This UI Page is going to expect a window property called “queryTerms”. This property will contain the short description of the incident. It will use those terms and stuff them into the DMOZ query URL in the iFrame src attribute. We are also setting the size of the iframe to be 700×300 pixels.

UI Macro

Name: Show Related DMOZ Results
Table: incident
Active: True
Client: True
List Context Menu: True
Onclick: showDmoz()
Script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function showDmoz() {
    //This code grabs the sys_id of the record that was right-clicked in the list
    var sysId = typeof rowSysId == 'undefined' ? gel('sys_uniqueValue').value : rowSysId;

    //We now will have to do a service query to get the short_description information
    var gr = new GlideRecord("incident");
    gr.get(sysId);

    //Set up the Dialog Window
    var w = new GlideDialogWindow('search_dmoz'); //pass in the name of the UI Page
    w.setTitle('Similar DMOZ Results');
    w.setPreference('queryTerms', gr.short_description); //pass in the query terms
    w.render();  //Show the dialog box
}

The End Result

A user will browse the incident list:
dmozBrowse

They will then right-click on an incident record:
maozRightClick

Then results will be shown in the dialog window:
dmozRes

JSONv2 Tutorial

$
0
0

One of the upcoming features of the Dublin Release at ServiceNow is an updated JSON Web Service processor. While it is still not an official REST API for the platform, it is a huge improvement on the original JSON processor that was release a few years ago.

Why the Update

The original JSON Web Service was created to address some basic needs that a handful of customers were requesting in order to use simple RESTful calls to interact with the ServiceNow platform. However, there were some serious performance issues and bulk data limitations that hindered the processor. Secondly, the original processor had some slight security issues that made the processor a risk to some organizations based on their use case. Lastly, the JSON Web Service was inconsistent with how its counterparts worked (eg. JSON web service issue with Web Service Import sets).

Due to the underlying issues in the JSON web service plugin, ServiceNow rewrote the plugin from scratch and worked to get it more similar to the capabilities our SOAP Web Services as well as our other CSV and XML processors for handling bulk data.

Starting with Dublin, ServiceNow will enable the JSONv2 plugin by default. They will also deprecate (and remove) the original JSON web service plugin (can possibly be loaded on special request). Additionally, the processor is now being moved to the Java code rather than using the Javascript implementation.

Rumor has it that the JSONv2 plugin will be made available for Calgary instances in the next publicly released Calgary Patch.

I highly recommend customers discontinue the use of the JSON Web Service plugin and migrate those integrations to be compatible with the JSONv2 format (not much has changed in the interface…so this shouldn’t be too hard).

General Information

The JSONv2 Web service will be accessed by using the URL parameter: “JSONv2″ (instead of the “JSON” parameter used by the original processor).

The JSONv2 Web Service can use either GET or POST requests for querying or deleting data. POST requests are required for creating or modifying data through the web service.

Like its predecessor, JSONv2 web service goes through a Basic Authentication layer for determining a client’s access to the resources being referenced.

A “Content-Type” header is now required on all requests. This will be important (and easy) to implement as you migrate old JSON web service clients over to JSONv2.

Using the JSONv2 Web Service

1) Set up the base URL

In order to access a table’s resources through JSONv2, you must reference the table URL that you are going to work with.

In ServiceNow, you can access a table resource by appending it’s database name to the end of the URL and then adding a “.do” exention. For example, the “Incident” table in ServiceNow has a Database Name of “incident”. You would form that URL in this manner:

https://MYINSTANCE.service-now.com/incident.do

For the “ECC Queue” table (ecc_queue), you would use:

https://MYINSTANCE.service-now.com/ecc_queue.do
2) Add the JSONv2 parameter
This is as simple as adding "JSONv2" or "JSONv2=true" to your URL. So, if you were accessing the incident table, your URL might look like:
https://MYINSTANCE.service-now.com/incident.do?JSONv2

3) Set your Content-Type Header

Remember that this header needs to be set. It is always going to have the same value, but you have to include it. Your header string would look something like:

Content-Type: application/json

4) Set your desired action

You can do the following actions with the Web Service (see the official documentation for definitions on what these actions do): get, getKeys, getRecords, insert, insertMultiple, update, deleteRecord, deleteMultiple.

If we wanted to do a getRecords call, we would set up our sysparm_action parameter in the following way:

https://MYINSTANCE.service-now.com/incident.do?JSONv2&sysparm_action=getRecords

5) Add additional parameters as needed

Depending on what you want to do, you will need/want additional URL parameters. The ones most commonly used by me are as follow:

  • displayvalue (true or false - if true, it returns display values instead of sys_id's for reference fields)
  • sysparm_view (a view name - limits what fields are returned with the record data - used with "getRecords")
  • sysparm_query (an encoded query to filter records - used with "getKeys", "getRecords", "deleteMultiple"
  • sysparm_record_count (limits amount of records returned - used with "getRecords" only)
  • sysparm_sys_id (used with "get" or "deleteRecord" only)

6) Add body content for the POST

If you are performing an insert, insertMultiple or an update, you will need to post the data in JSON format as the Body of the HTTP POST request. For more information on the format, see the wiki documentation for JSONv2 Data Modification.

Example usage of the JSONv2 Web Service

In the following example, we are going to query the incident table of an instance. Since we may have more incident records that are allowed, we are going to limit the number of returned records and chuck the requests. Also, we don't care about a lot of the fields, so we are only going to require the fields from the "mobile" view to be returned through the web service calls. Finally, we will request display values rather than sys_ids for reference fields.

Let's follow our steps to generate the first RESTful request:

1) Set up the URL to operate against the incident table

https://MYINSTANCE.service-now.com/incident.do

2) Invoke the JSONv2 Processor

https://MYINSTANCE.service-now.com/incident.do?
 JSONv2

3) Set the Content-Type to "application/json"
4) Specify the "getRecords" action

https://MYINSTANCE.service-now.com/incident.do?
 JSONv2
 &sysparm_action=getRecords

5) Use some optional parameters to get what we want
We will ask for display variables to be returned for reference fields:

https://MYINSTANCE.service-now.com/incident.do?
 JSONv2
 &sysparm_action=getRecords
 &displayvalue=true

We will restrict the number of fields to just those of the mobile view:

https://MYINSTANCE.service-now.com/incident.do?
 JSONv2
 &sysparm_action=getRecords
 &displayvalue=true
 &sysparm_view=mobile

We will want to order the results by sys_id since we are going to page through them:

https://MYINSTANCE.service-now.com/incident.do?
 JSONv2
 &sysparm_action=getRecords
 &displayvalue=true
 &sysparm_view=mobile
 &sysparm_query=ORDERBYsys_id

We will page the data to manageable sets. For this example, we will say "3" records. That is really low, but this is just a demo:

https://MYINSTANCE.service-now.com/incident.do?
 JSONv2
 &sysparm_action=getRecords
 &displayvalue=true
 &sysparm_view=mobile
 &sysparm_query=ORDERBYsys_id
 &sysparm_record_count=3
1
https://MYINSTANCE.service-now.com/incident.do?JSONv2&sysparm_action=getRecords&displayvalue=true&sysparm_view=mobile&sysparm_query=ORDERBYsys_id&sysparm_record_count=3

This will get us the following response:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
{
    "records": [
        {
            "__status": "success",
            "vendor_point_of_contact": "Whale",
            "caller_id": "Celia Slavin - Test",
            "work_notes": "",
            "vendor": "IBM",
            "state": "Closed",
            "sys_id": "06a4b716eb920100a9e7e26ac106feb6",
            "number": "INC0003027",
            "assigned_to": "ITIL User - Test",
            "category": "Inquiry / Help",
            "short_description": "IBM Cloud Computing is experiencing turbulence.",
            "priority": "2 - High",
            "vendor_ticket": "IBM20203",
            "assignment_group": "Service Desk",
            "comments": "2013-10-27 09:11:49 - System Administrator (Additional comments)\nThe incident has been resolved.\n\n"
        },
        {
            "__status": "success",
            "vendor_point_of_contact": "Tom",
            "caller_id": "Dionne Borycz - Test",
            "work_notes": "",
            "vendor": "Amazon",
            "state": "(-8)",
            "sys_id": "135df534df120100cd7da5f59bf26302",
            "number": "INC0003005",
            "assigned_to": "ITIL User - Test",
            "category": "Inquiry / Help",
            "short_description": "Amazon EC2 appears to be down",
            "priority": "2 - High",
            "vendor_ticket": "AMZ41103",
            "assignment_group": "Service Desk",
            "comments": ""
        },
        {
            "__status": "success",
            "vendor_point_of_contact": "Watson",
            "caller_id": "Nelly Jakuboski - Test",
            "work_notes": "",
            "vendor": "IBM",
            "state": "(-8)",
            "sys_id": "1a0db534df120100cd7da5f59bf26304",
            "number": "INC0003004",
            "assigned_to": "ITIL User - Test",
            "category": "Inquiry / Help",
            "short_description": "Cloud computing db down",
            "priority": "5 - Planning",
            "vendor_ticket": "IBM88108",
            "assignment_group": "Service Desk",
            "comments": ""
        }
    ]
}

Those are the first three records. We are then going to take the sys_id from the last record and query for the next set of records with the following URL:

https://MYINSTANCE.service-now.com/incident.do?
 JSONv2
 &sysparm_action=getRecords
 &displayvalue=true
 &sysparm_view=mobile
 &sysparm_query=sys_id>1a0db534df120100cd7da5f59bf26304^ORDERBYsys_id
 &sysparm_record_count=3
1
https://MYINSTANCE.service-now.com/incident.do?JSONv2&sysparm_action=getRecords&displayvalue=true&sysparm_view=mobile&sysparm_query=sys_id>1a0db534df120100cd7da5f59bf26304^ORDERBYsys_id&sysparm_record_count=3

This gets us the next set of three.

Handling special Content-Types in a Processor

$
0
0

basicform-2

In ServiceNow processors, you have the nice getParameter() function to get a POST or GET url parameter. However, processors work differently depending on the Content-Type of the HTTP request. I wrote a few functions that work with three of the more popular content types that I use.

application/x-www-form-urlencoded

With this Content-Type the information comes in as one URL parameter. That URL parameter name is a JSON string of all of the posted information. There is no value to that parameter. You have to get the enumeration of the parameters and then convert the parameter to a Javascript object.

Here is the function:

1
2
3
4
5
6
7
function getURLEncodedFormParam(paramName) {
  var urlParamList = g_request.getParameterNames();
  var paramsEl = urlParamList.nextElement();
  var json = new JSON();
  var params = json.decode(paramsEl);
  return params[paramName];
}

multipart/form-data

This Content-Type will store the various parameters as a JSON string in the body of the request. You need to read the body of the request and then convert it to a Javascript Object.

1
2
3
4
5
6
7
function getMultipartFormDataParameter(paramName){
  var is = g_request.getInputStream();
  var sb = GlideStringUtil.getStringFromStream(is);
  var json = new JSON();
  var params = json.decode(sb);
  return params[paramName];
}

The “application/json” content-type will also use this method of grabbing parameters.

Mutual Authentication and ServiceNow

$
0
0

Anytime anyone wants to talk about security, certificates, and certificate authorities most people zone out as if they were on a dinner date and everyone started to talk about religion or politics (and yes, I love to talk religion and politics).

Besides being able to send and receive signed Web service requests using WS-Security, ServiceNow is also able to consume web services that require mutual authentication. Mutual authentication is also known as mutual SSL authentication, two-way SSL authentication, or certificate-based mutual authentication. With this method of authentication, two parties authenticate to each other by each verifying signed certificates provided by the other entity. This “handshake” process takes place before any web service payload is exchanged.

Please Note: While ServiceNow Web service clients can be configured to make SOAP, REST, or other Web service requests with mutual authentication, operational and data center constraints current prohibit ServiceNow from supporting inbound mutual authentication requests.

General setup to prepare for Mutual Authentication

Before you can perform mutual authentication, there are some steps that are required to be set up between a client and a server. Within this article, we will refer to ServiceNow as the client, and a third-party service as the server.

STEP 1 – Generate Signed Certificate for ServiceNow

Screenshot_12_17_13_7_37_AM

A certificate must be generated and signed for the ServiceNow instance. For demo purposes a self-signed certificate is usually just fine. However, in production systems, you will likely want to generate a certificate and have it signed through a trusted Certificate Authority.

If I were to generate a self-signed certificate for testing, I might do the following:

1
2
#Generate the certificate, sign it, and create a keystore to put it in
keytool -genkey -alias snclient -keyalg RSA -validity 365 -keystore snclient.keystore -storepass abcd1234 -keypass abcd1234

The tool will prompt me with several questions that I can answer:

Screenshot_12_17_13_7_49_AM

Once I complete this, my certificate and private key will be generated and stored in a java keystore file named: “snclient.keystore”. Both the keystore and the private key will have a password of “abcd1234″.

STEP 2 – Upload keystore to ServiceNow

Screenshot_12_17_13_7_38_AM

The keystore containing the certificate and private key will need to be uploaded into the ServiceNow instance.

Sample Keystore Setup in ServiceNow

Sample Keystore Setup in ServiceNow

To do this, browse to System Definition > Certificates. Click New. Give the record a name, and then set the Type field to be Java Key Store. Type in the keystore password (in this example, I used “abcd1234″). Finally, attach the keystore file to the record and then click the Submit button.

STEP 3 – Share public certificate with third party service

Screenshot_12_17_13_7_41_AM

The Public Certificate that was generated for the ServiceNow instance should be shared with the third party service you will be consuming. You can do this in any format that they third party requires. Usually a certificate in the DER format (.cer file) is sufficient. If you had your certificate signed by a Certificate Authority, it is good to send all of the certificates involved in the certificate chain used by the signing authority.

In order to extract the public certificate from the keystore we created, we can issue the following command:

1
keytool -export -alias snclient -keystore snclient.keystore -storepass abcd1234 -file snclient.cer

This gives me a public certificate file in the “DER” format by the name of “snclient.cer”. I can now give this to the person managing the third party service so that they can load it into their trust store.

STEP 4 – Load the third party certificate into ServiceNow

Ask for the third party certificate in either PEM or DER format. If the certificate is involved in a trust chain, ask for the corresponding certificates as well. Load the certificate(s) into the ServiceNow instance by browsing to System Definition > Certificates. Click New. Give the record a name, and then set the Type field to be Trust Store Cert.

If the certificate was in PEM format, set the Format field to PEM and paste the PEM string into the PEM Certificate field on the record. Be sure to include the “—— BEGIN CERTIFICATE ——-” and “———- END CERTIFICATE ———-” strings.

If the certificate was in DER format, set the Format field to DER and attach the certificate file to the record.

Sample Certificate Record loaded in DER format.

Sample Certificate Record loaded in DER format.

After you click Submit the record will be populated through the information in the certificate.

STEP 5 – Set up Mutual Authentication Protocol properties

ServiceNow lets you define your own protocol and port for communicating with an endpoint that requires Mutual Authentication. When you use that protocol class, it triggers the mutual authentication.

For example, I can choose to create a protocol class of “myhttps”. When this protocol class is used in an Endpoint in the system, it automatically triggers mutual authentication over a specified port.

A SOAP request going to “https://myexample.com/SOAPWebService/ticket” will post without Mutual Authentication over HTTPS on port 443.

I can set up two properties in the ServiceNow instance that lets me trigger the mutual authentication.

  • glide.httpclient.protocol.DESIREDPREFIXSTRING.class
  • glide.httpclient.protocol.DESIREDPREFIXSTRING.port

The first property must be set to the following java class signature: “com.glide.certificates.DBKeyStoreSocketFactory”.
The second property can be set to whatever port the third party is running on (it can even be port 443).
Both properties should have the same DESIREDPREFIXSTRING value in the property name.

For example, let’s say I set the properties up in the following manner:
mauthprops-2

In this case, if I change my previous SOAP endpoint to be: “myhttps://myexample.com/SOAPWebService/ticket”, this will trigger the request to go over port 6767 and perform a mutual handshake before sending the payload. The key is the “myhttps” protocol prefix. This prefix can be whatever you want, as long as it is not already used by the system.

To view the video demo that covers this and the actual setup/execution of a Mutual Authentication call within ServiceNow, view the How to set up Mutual Authentication video link.

Scriptable RESTMessage Library for ServiceNow

$
0
0

ServiceNow has always been great to make traditionally difficult integration interfaces easy to setup and execute. This typically translates into a lot of point and click activities.

For the die-hard coders, like me, sometimes we want a little less point and clickedness to get our job done.

For example, if you want to consume a REST based API that has many different API calls, you would traditionally have to create several REST Message records within the ServiceNow platform. Each record would have its own function headers, endpoint, request parameters, variables, etc. While it makes it easy to understand, it can introduce a lot of steps.

In order to bypass the UI and go straight into REST-based API consumption, I have created a Script Include that extends the current “RESTMessage” library and adds 100% scripting capabilities. This library is called “RESTMessageScripted”.

Documentation

RESTMessageScripted( httpFunctionName, endpointURL )
Cosntructor
httpFunctionName: “get”, “put”, “post”, “delete”
endpointURL: the full URL string for the REST endpoint

Example(s):

1
var r = new RESTMessageScripted("get", "https://myinstance.service-now.com/incident.do");
1
var r = new RESTMessageScripted("post", "https://login.salesforce.com/services/oauth2/token");

addheader( name, value )
Adds an HTTP Header name/value pair to the request. The system will issue these headers in the order that they were added.
name: a string representation of the header name
value: a string representation of the header value

Example(s):

1
2
3
var r = new RESTMessageScripted("get", "https://myinstance.service-now.com/incident.do");
r.addHeader("Content-Type", "application/json");
r.addHeader("Content-Accept", "application/json");

addRequestParameter( name, value )
Adds an HTTP Request parameter to the request. The system will issue these request parameters in the order that they were added.
name: a string representation of the parameter name
value: a string representation of the parameter value (note: values will be URL Encoded automatically.)

Example(s):

1
2
3
var r = new RESTMessageScripted("get", "https://myinstance.service-now.com/incident.do");
r.addRequestParameter("JSONv2", "true");
r.addRequestParameter("sysparm_query", "active=1^priority=1");

setContent( content )
Sets the Request Body Content (Used for POST and PUT functions). Otherwise this is just ignored.
content: a string representation of the full body content of the POST or PUT request.

Example(s):

1
2
3
4
5
6
var r2 = new RESTMessageScripted("post", "https://myinstance.service-now.com/incident.do");
r2.addHeader("Content-Type", "application/json");
r2.addRequestParameter("JSONv2", "true");
r2.addRequestParameter("sysparm_action", "insert");
r2.setBasicAuth("admin", "myadminpassword");
r2.setContent('{"short_description":"Hello world 4 56", "cmdb_ci":"DatabaseServer2"}');

execute()
Executes the REST call. If the REST call is synchronous, it will return the traditional RESTResponse object that is currently returned by the OOB RESTMessage class. If the REST call is asynchronous (via MID Server), no response is returned.

Example(s):

1
2
3
4
5
6
7
var r = new RESTMessageScripted("get", "https://myinstance.service-now.com/incident.do");
r.addHeader("Content-Type", "application/json");
r.addRequestParameter("JSONv2", "true");
r.addRequestParameter("sysparm_query", "active=1^priority=1");
r.setBasicAuth("admin", "myadminpassword");
var response = r.execute();
gs.log(response.getBody());
1
2
3
4
5
6
7
8
var r2 = new RESTMessageScripted("post", "https://myinstance.service-now.com/incident.do");
r2.addHeader("Content-Type", "application/json");
r2.addRequestParameter("JSONv2", "true");
r2.addRequestParameter("sysparm_action", "insert");
r2.setBasicAuth("admin", "myadminpassword");
r2.setContent('{"short_description":"Hello world 4 56", "cmdb_ci":"DatabaseServer2"}');
r2.setMIDServer("MID2");
var response2 = r2.execute();

All other functions associated with with out-of-box RESTMessage library are still available. They include:
  • setBasicAuth( username, password )
  • setMIDServer( midServerName )
  • setRestEndPoint( endpointURL )

All responses and behaviors from this library are the same as those processed by the RESTMessage library. Please see the following two documents for more information:

Contribute on GitHub

I have created a respository on GitHub so that others can help contribute and fix any issues with the library. You can get access to the repository at: Scripted Rest Messages on GitHub.

Installation Instructions

This is a ServiceNow Update Set file in XML format. Simply upload it into your instance using the instructions on loading XML-based Update Sets into your Instance.

Once you have loaded, previewed, and committed the update set, you will be able to access the library in your scripts.

Download

Click below to download your item:
This file is not supported nor authored by Service-now.com. Please use at your own risk.

Newsletter Application for ServiceNow

$
0
0

I was recently asked to provide a newsletter for several internal teams within our company. The first few months were a pain as I had to use an HTML editor to generate a decent looking newsletter each time I wanted to get the word out on some articles that I have been creating. Finally, I asked myself why I was going through all this pain when ServiceNow would be the perfect platform to build a newsletter application that automates most of the tasks.

201402-February_html

Within a couple of days I had a pretty decent application that would allow me to create newsletters with templates, dynamic variables, scripting capability, and article management. Since then, the writing of my newsletters have become much easier to do. Organizing my articles and sending them out to distribution lists are so much better than my copy and paste solution with my previous method.

I’ve decided to share this application with others who would like to take it and implement it within their own instance. It is not perfect, and there are several and him that I would like to perform in the future. However, if you’re not afraid to play with it, I think you will find it to be a great help to you in creating your own newsletters.

The Application

Screenshot_2_6_14_11_24_AM

The application comes with two basic roles. The first role is the newsletter user role. This user can create and manage templates, articles, variables, and newsletters themselves. They can also send out the newsletters when they are ready.

The second role is a newsletter administrator role. The newsletter administrator can do everything that the newsletter user role can do. In addition, it has access to the settings, the scripts and diagnostics sections of the application. This allows the newsletter administrator user the ability to change how the application works.

There are four main components of the newsletter creator. The first is the concept of a newsletter template. This allows you to generate HTML and text based templates that determine the look and feel of the newsletter when it is generated and published. The next component is the newsletter articles. Each article is its own record and has both an HTML format as well as a plain text format. The third component is the newsletter variable object. Variables can be used with a newsletter templates. They allow for dynamic content changes within a newsletter from issue to issue. Finally, the fourth component is the newsletter itself. The newsletter record as a template associated with it along with articles and variables. It is from the newsletter that the final draft is generated and can be sent out to recipients.

Newsletter Templates

The newsletter application comes with several different templates. Some of these templates are very basic, while others are more complicated. Templates include a WYSIWYG editor that can be used for basic HTML formatting. If you would like to get more complex, you can click the HTML button within the editor and utilize CSS and HTML tags to build out a more precise template.

Screenshot_2_6_14_11_55_AM

Templates leverage variables to allow dynamic content to be entered into the newsletter with each newsletter edition. This allows you to change month names, article content, or sidebar content in your newsletter without having to modify the template every time. Variables are denoted in the template record with a “${}” notation. For example, if I had a variable by the name of “month”, I would insert it into the template as: ${month}.

There are two groups of variables that are available within a template. The first group is a set of prebuilt variables. These variables come from the newsletter record and others are special for the article insertion:

  • NL_title – The value of what is in the newsletter’s “Title” field
  • NL_subtitle – The value of what is in the newsletter record’s “Subtitle” field
  • article_list and /article_list – These variables are similar to HTML tags. They denote the section within the template that will be replicated for every article associated with the newsletter.
  • article_title – This is the value of the article record’s “Title” field. It will be generated for each article associated with the newsletter.
  • article_body – this is the value of the article record’s “Body” content field.

The second group of variable available within the template is a newsletter variable. These are variables that are defined on the newsletter record and are independent of the template. These variables can have any name that you wish as long as it is not one of the prebuilt variable names mentioned above.

For examples on how these variables are leveraged within a template, check out the examples that come with the application.

Newsletter Variables

Newsletter variables are declared from within the newsletter record itself. These variables are associated with that particular newsletter. When you generate the draft of your newsletter, those variables will be applied to the template.

Screenshot_2_6_14_11_56_AM

When declaring variables on a newsletter record, you need to understand the difference between the two types of variables that are available to you. The first type of variable is a “Text variable.” This variable contains a static string that will replace the variable once the newsletter is generated. For example, if I have a variable called “month”, and the value is set to “January”, Then when my newsletter is generated, the ${month} text within the template will be replaced with: “January”.

The second type of newsletter variable is a script-based variable. These variables contain JavaScript rather than a plain-text value. In these variables, you execute your script and save the result of the script to a variable. That variable should be the last line of your script. Whatever that variable contains at the end of the script execution is what will be used to replace the variable within the template. These are useful if you want to build a dynamic table of contents, pull an RSS feed in from another location, or insert your company’s latest stock quote.

The following example is a newsletter script that builds out a couple of links for the newsletter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var answer = "";
var links = [
    ["http://www.john-james-andersen.com/blog/service-now/scriptable-restmessage-library-for-servicenow.html",
        "Scriptable Rest message Library"
    ],

    ["http://www.john-james-andersen.com/blog/service-now/mutual-authentication-and-servicenow.html",
        "Mutual Authentication and ServiceNow"
    ],
];

for (var key in links) {
    answer += '&bull; <a href="' + links[key][0] + '">' + links[key][1] + '</a><br/>\n';
}
answer; //Whatever is here is what replaces the variable in the template

Newsletter Articles

Each newsletter article record should contain one article. You can define the article title as well as both an HTML body as well as a plain text body. You have the same HTML editor capabilities as you do with the newsletter template. This provides you some great flexibility in creating a particular article.

Screenshot_2_6_14_12_25_PM

You can create articles either from the “Newsletter Article” module within the application, or from a newsletter record as well. When creating a newsletter article from a newsletter record, the article will automatically be associated with that newsletter edition. Articles that are created from the module must be assigned to newsletters manually.

Newsletter article records also contain an “order” field. When you associate articles to a newsletter, the articles will be ordered relative to the various order values set on each article. The lower the number, the higher up it will appear in the newsletter.

I like to create articles throughout the month as newsworthy items occur. Then, near the end of the month, I associate the articles to the various newsletters that I’m going to send out.

The Newsletter Record

The newsletter record is the center place of managing your newsletters. you can create articles, managed templates, and create variables from the newsletter record.

Screenshot_2_6_14_12_18_PM

The “Title” and “Subtitle” fields are what feed the “NL_title” and “NL_subtitle” variables in the Newsletter Template.

The “Recipients” field on the newsletter form allows you to add email addresses for each individual that is to receive your newsletter. I like to do one email address per line in this field. At this point in time, I do not have a feature for subscribing and unsubscribing to a newsletter, or using any type of member management system.

The “Subject Line” field is what will be placed in the email’s subject line when the newsletter is sent.

When you have all the components of your newsletter compiled and organized, you can click the “Generate” button on the form to generate a preview of your newsletter in the HTML and plain text fields. Please note, if you have anything in those fields to begin with, they will be overwritten when the newsletter is generated. I debated on making these two fields read-only, however, I decided it might be useful to allow the user to make slight modifications to the newsletter after it was generated.

Once you are happy with your newsletter and you are ready to send it out to the recipients, click the “publish to recipients” link at the bottom of the form. This will schedule an email to be sent out to each email address that was listed in the recipients field on the form.

Demo Video

Update Set

Click below to download your item:
This file is not supported nor authored by Service-now.com. Please use at your own risk.


Getting all fields with CSV export in ServiceNow

$
0
0

Screenshot_2_12_14_2_23_PM

I am so excited, that I am almost giddy. If you knew me well, you would know that this is not a very common state of mind for me. I am a pretty rational and calm guy. However, I overheard some chatter within the ServiceNow communities and learned that there is a new option with the ServiceNow export feature that allows you to get all field that I use with a CSV export.

For years, if you performed a CSV export you would only get fields that were exposed on the list view for that table. There were special parameters that allowed you to use a list view to get different fields than what existed on the default list view. However, there was no way to export the sys_id field off of that table. The community forest with lots of creative solutions to get the sys_id field, but no out-of-the-box solution allows you to get it from the table itself.

I have just learned that with the Dublin release you can now pull the sys_id field along with all the other fields by adding the following URL parameter:

sysparm_default_export_fields=all

So, if I wanted to export incidents from my incident table, my Request URL might look like the following:

https://myinstance.service-now.com/incident.do?CSV&sysparm_default_export_fields=all

I have tried this out personally, and found it to work splendidly. It is exciting to finally see this simple enhancement request, to life! Many thanks to my ServiceNow colleagues who brought this to my attention. Many more things to the development team who got us into the product.

Unauthenticated Access to ServiceNow WSDL’s

$
0
0


http://youtu.be/hTo0YEQhiXA

The ServiceNow Dublin release includes a new enhancement around security protecting the WSDL resources on a ServiceNow instance. In the past, you had two options with regard to controlling who could view your WSDL documents. One, you could require a user to authenticate before they could see the WSDL. Two, you could allow anyone to see the WSDL document. All this was controlled by a simple checkbox in the web services security properties page.

ServiceNow-3

The Dublin release now allows you to protect your WSDL documents by requiring the soap or admin role as well as the requirement to authenticate to view the WSDL. Now, with this requirement, only those with Web services capabilities can see the WSDL documentation.

While this added level of security is great, it does make it a little bit more difficult for those who wish to allow unauthenticated access to their WSDL documents. Why would you ever want to do this? Some web service clients do not have the ability to authenticate during a WSDL query and thus are blocked from getting the WSDL. There are usually workarounds for this, but a lot of people are okay with public access to WSDL documentation because it only describes the web service rather than gives anyone access to use it.

With the Dublin release and beyond, if you wish to make your WSDL documents accessible without authentication, you will still need to uncheck the system property that requires authentication for WSDL access. In addition to this, you will need to go to the access control list and look up the access control record for the “WSDLProcessor”. Once you find this access control record, simply deactivate the ACL.

ServiceNow-2

For more information on this change, as well as a live demo of making a WSDL document public in Dublin, please see the video at the top of this blog post.

New CTI Rule – Always Show the Incident Form

$
0
0

CTIIncidentForm

The current CTI Integration within ServiceNow allows third party phone agents to do a screen-pop to send call data to the ServiceNow instance to pre-populate a ticket or do other activities. By default, the CTI integration will take the call information and determine if the caller already has open tickets associated to them. If they do, the system will show that user’s record with a list of their open incidents and assigned configuration items.

While this feature is great, a lot of companies want to bypass this feature and open a new incident form regardless of whether or not the caller already has open tickets.

The following solution creates a new CTI Rule in a ServiceNow instance to give your Call Agent System the opportunity to force open a new incident record regardless of the number of open tickets already associated to the user.

This solution does not change the CTI interface in any way as it leverages the extensibility portion of the CTI integration. You can leverage the same URL parameters as the standard interface. To have your system trigger this rule rather than the standard one, you simply add the following URL parameter to your URL: sysparm_cti_rule=cti_inc

For example, lets take the scenario of Fred Luddy calling into the help desk. Fred already has active tickets open. Let’s contrast the OOB rule with this rule:

OOB Rule

URL:

https://MYINSTANCE.service-now.com/cti.do?
              sysparm_caller_name=Fred%20Luddy
              &sysparm_impact=1
              &sysparm_short_description=My%20CTI%20Posted%20Ticket

RESULT:
CTIOld

Notice how the system shows the User Record, rather than a New Incident form.

This New Optional Rule

URL (notice the last URL Parameter):

https://MYINSTANCE.service-now.com/cti.do?
              sysparm_caller_name=Fred%20Luddy
              &sysparm_impact=1
              &sysparm_short_description=My%20CTI%20Posted%20Ticket
              &sysparm_cti_rule=cti_inc

RESULT:
ServiceNow_Service_Automation

As you can see, the extra URL parameter bypassed the User Record view and forced the system to still pre-fill an incident record for the caller.

Download

You can currently download this solution from the ServiceNow Share Portal:

CTI Rule: Always Show incident Form

Sample SolarWinds Alert Handler in ServiceNow

$
0
0

redalert

SolarWinds is a popular event management/monitoring tool that is often integrated into ServiceNow. Most folks that I know have done this integration via Inbound Email Actions.

I worked with a client a year ago that wanted to leverage the ability of SolarWinds to perform an HTTP Post to a URL whenever there was a qualifying alert. They wanted to configure ServiceNow to handle that POST and create an Incident record in their ServiceNow instance.

This particular client was okay with the endpoint being a public endpoint that did not require authentication. We were able to quickly configure their instance to accept these inbound HTTP posts from solar winds using a small scripted processor.

Please note that this is not a production script. It is generic in nature so you can build it out to your own needs. It could easily be enhanced to handle other parameters from the SolarWindows alert coming into the instance.

The Processor

Name: solarwind_alert
Active: true
Type: script
Path: solarwind_alert
Script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var alarm = new Object();

/*
 * We could iterate through all of the URL parameters to make
 * intelligent decisions about how to handle this request,
 * but in this example, we will just write each URL parameter
 * and its value to a logging string
 */

var urlParamList = g_request.getParameterNames();
var paramMsg = ""; //we're going to log parameter info here
while(urlParamList.hasMoreElements()){
    var param = urlParamList.nextElement();
    var value = ""+g_request.getParameter(param);
    paramMsg += ("Parameter: ["+param+"] has a value of: "+value+"\n");
  alarm[param] = value;
}

//Possible Debug Logging statements if needed
//gs.log("Parameters: " + paramMsg);
//JSUtil.logObject(alarm);

var gr = new GlideRecord("imp_notification");
gr.initialize();
gr.message = alarm.description;
gr.comments = alarm.description;
gr.source = alarm.asset;
//For this example, we assume every alert coming it is unique
//and therefore are just setting a random UUID for the alert.
//In real life this would be an alert or alarm ID coming from
//SolarWinds
gr.uuid = Math.floor((Math.random()*1000000)+1);
gr.insert();

Of course we had to add this alert to the sys_public table in the instance so that SolarWinds could POST to it without authenticating.

ServiceNow_Service_Automation

Now the SolarWinds system just needed to be configured to post its alert data to:

https://MYINSTANCE.service-now.com/solarwind_alert.do

A New REST API Unveiling at K14

$
0
0

The upcoming Eureka Release is rumored to be sporting a brand new, official REST platform API. I am honored to take my place on stage next to some genius-developers to demonstrate the new interface.

electjohn

To find out what this picture has to do with this announcement, don’t miss the 50 minute breakout session where we will unveil the API and I announce my candidacy in a very important race.

Here is the not-to-be-missed Session:

Rapid App Integrations With The New REST API
April 30, 2014 1:40 PM-2:30 PM in Moscone West 3022

Have an idea for an App? Lets create one together and show how easy it is to create cool integrations via the new REST API!

In this session, ServiceNow will take you through creation of an application, show you how to insert data into that app, and showcase how to expose that data to a native IOS application. All of this is powered by the REST API coming in the next release (Eureka) from ServiceNow.

Speaking at this session
Mark Brennan
Director – Cloud Platform
ServiceNow

Silas Smith
Cloud Platform
Developer
ServiceNow

John Andersen
Solution Architect
ServiceNow

Add us to your Knowledge 14 calendar today!

Viewing all 82 articles
Browse latest View live