CA Service Desk

CA Service Desk provides a SOAP web service that allows provides you with queries and operations into the Service Desk software. The WSDL to their API can be found at:

http://YOUR_CA_SERVICE_DESK_SERVER:8080/axis/services/USD_R11_WebService?wsdl

In the following example, I created a Script Include that handles authentication as well as database style queries through the “doSelect” web service function as well as creating activity logs through the “createActivityLog” function.

Before we get into the code I wrote, we need to outline the the SOAP Functions that I created in ServiceNow to connect to CA Service Desk.

Please note, for the full WSDL, feel free to download the CA Service Desk WSDL wsdl document.

I used this WSDL document to create a SOAP Message record which I named “CA Service Desk”.

CA Service Desk Login Service

In order to use the SOAP API, you must first authenticate using the Login Service. The response to this call will return a token that you must use in your subsequent calls into the API.

Here are the ServiceNow SOAP settings I used for Authentication:
SOAP Message Function: login
SOAP Action: Login
SOAP Endpoint: http://YOUR_SERVER:8080/axis/services/USD_R11_WebService
Envelope:

1
2
3
4
5
6
7
8
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:m="http://www.ca.com/UnicenterServicePlus/ServiceDesk"  SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <login xmlns="http://www.ca.com/UnicenterServicePlus/ServiceDesk">
      <username xsi:type="xsd:string">${username}</username>
      <password xsi:type="xsd:string">${password}</password>
    </login>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

CA Service Desk doSelect Service

This service lets you query the backend database in Service Desk.

SOAP Message Function: doSelect
SOAP Action: doSelect
SOAP Endpoint: http://YOUR_SERVER:8080/axis/services/USD_R11_WebService
Envelope:

1
2
3
4
5
6
7
8
9
10
11
12
13
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:m="http://www.ca.com/UnicenterServicePlus/ServiceDesk"  SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <doSelect xmlns="http://www.ca.com/UnicenterServicePlus/ServiceDesk">
      <sid xsi:type="xsd:int">${sid}</sid>
      <objectType xsi:type="xsd:string">${objectType}</objectType>
      <whereClause xsi:type="xsd:string">${whereClause}</whereClause>
      <maxRows xsi:type="xsd:int">${maxRows}</maxRows>
      <attributes xsi:type="m:ArrayOfString">
        ${attributes}
      </attributes>
    </doSelect>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

CA Service Desk createActivityLog Service

This web service creates an activity within Service Desk

SOAP Message Function: createActivityLog
SOAP Action: createActivityLog
SOAP Endpoint: http://YOUR_SERVER:8080/axis/services/USD_R11_WebService
Envelope:

1
2
3
4
5
6
7
8
9
10
11
12
13
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:m="http://www.ca.com/UnicenterServicePlus/ServiceDesk"  SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <createActivityLog xmlns="http://www.ca.com/UnicenterServicePlus/ServiceDesk">
      <sid xsi:type="xsd:int">${sid}</sid>
      <creator xsi:type="xsd:string">${creator}</creator>
      <objectHandle xsi:type="xsd:string">${objectHandle}</objectHandle>
      <description xsi:type="xsd:string">${description}</description>
      <logType xsi:type="xsd:string">${logType}</logType>
      <timeSpent xsi:type="xsd:int">${timeSpent}</timeSpent>
      <internal xsi:type="xsd:boolean">${internal}</internal>
    </createActivityLog>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Helper Script Include Library

The following helper functions allow you to leverage the SOAP Messages with very little worry about authentication, roles, etc. It will attempt to perform the operation. If there is no current user token, then it will perform a Login call and then use the token to execute the desired call.

Please note that for this example, the username and password are embedded in the code rather than queried as system properties.

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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
var CASDHelper = Class.create();
CASDHelper.prototype = {
   logSource: "CASD-Integration",
   initialize: function() {
      this.logLevel = gs.getProperty("com.snc.integration.usd.loglevel", "3");
   },
       
    /*
    * Authenticates into CA Service Desk and gets a session ID token
    * There is typically need to call this function manually since primary query functions
    * will auto detect whether a new sessionID token is required.
    */

   usdLogin:function() {
     
      var s = new SOAPMessage('CA Service Desk', 'login');
      s.setParameter('username', 'MYUserName');
      s.setParameter('password', 'MYPassword');
      s.post();
      obj = this.getResponse(s);
     
     
      if(obj['soapenv:Body'] && obj['soapenv:Body'].loginResponse && obj['soapenv:Body'].loginResponse.loginReturn) {
         var sid = obj['soapenv:Body'].loginResponse.loginReturn['#text'];
         this.log("LOGIN returns a SID of: " + sid);
         gs.setProperty("com.snc.integration.usd.sid", sid);
         return sid;
      }
   },
   /*
    * Invalidates the current Session ID used by the ServiceNow instance
    */

   usdLogout: function() {
    var s = new SOAPMessage('CA Service Desk', 'logout');
    var sid = gs.getProperty("com.snc.integration.usd.sid","");
    s.setParameter('sid', sid);
    s.post();
    gs.setProperty("com.snc.integration.usd.sid","");
   },
   
   /*
    *
    * Perform a database query against CA ServiceDesk
    *
    * PARAMETERS
    *   objType - object being queried (eg. "cr")
    *   query - the actual query string (eg. "ref_num = '5253708')
    *   maxRows - max number of results to return
    *   attributes - Array of attribute names that we want returned in the query
    *     (eg. ["description", "persistent_id"])
    *   login - (default: false) Force a login first. Do not attempt to reuse an stored sessionID's
    *     Please note: this method, by default, will attempt to perform the action
    *        against the last used session id.  If that fails, we will force login    
    *        
    * RETURN
    *
    * Single or Array of object with the following members
    * .Handle - the id of the current record in the table
    * .Attributes[] - An array of returned attribute name/value pairs
    * .Attributes[].AttrName - The attribute name
    * .Attributes[].AttrValue - the value of the attribute
    *
    * RETURN OBJECT EXAMPLES
    * 1) Single Record Response - get First Attribute Value
    *   var object = a.usdDoSelect("cr", "ref_num='5253708'", 10, ["description", "persistent_id"]);
    *   var val = object.Attributes.Attribute[0].AttrValue;
    * 2) Multiple Reocrd Response - get first record's first Attribute Value
    *   var object = a.usdDoSelect("cr", "ref_num<'5253708'", 10, ["description", "persistent_id"]);
    *   var val = object[0].Attributes.Attribute[0].AttrValue;
    */

   usdDoSelect: function( objType, query, maxRows, attributes, login ){
      if(!login){
         this.log("Calling USD doSelect -- attempting to reuse a previous SID token");
         login = false;
      } else {
         this.log("Calling USD doSelect -- forcing a login first");
      }
      var attribs = "";
      for(key in attributes){
         attribs += "<string xsi:type='xsd:string'>"+attributes[key]+"</string>";
      }
      if(login){
         var sid = this.usdLogin();
      } else {
         sid = gs.getProperty("com.snc.integration.usd.sid","");
      }
     
      if(sid != ""){
         
         var s = new SOAPMessage('CA Service Desk', 'doSelect');
         s.setStringParameter('whereClause', query);
         s.setStringParameter('sid', sid);
         s.setXMLParameter('attributes', attribs);
         s.setStringParameter('objectType', objType);
         s.setStringParameter('maxRows', maxRows);
         s.post();
         var obj = this.getResponse(s);
         if(this.logLevel >= 3){
           JSUtil.logObject(obj);
         }

         if( obj['soapenv:Body'] && obj['soapenv:Body'].doSelectResponse && obj['soapenv:Body'].doSelectResponse.doSelectReturn && obj['soapenv:Body'].doSelectResponse.doSelectReturn.UDSObjectList){
            var udsObject = obj['soapenv:Body'].doSelectResponse.doSelectReturn.UDSObjectList.UDSObject;
            if(udsObject){
               return udsObject;
            }
         }
      }
     
      if( sid == "" || (login==false && this.usdCheckForLoginError(obj))){
         return this.usdDoSelect(objType, query, maxRows, attributes, true);
      }
     
   },
   
   /*
   * Creates a Log entry against a specified record
   *
   * PARAMETERS
   * handle - handle/id of the record we will be logging against
   * message - the message being posted
   * login - (default: false) Force a login first. Do not attempt to reuse an stored sessionID's
   *    Please note: this method, by default, will attempt to perform the action
   *      against the last used session id.  If that fails, we will force login
   *
   * Returns the handle string of the activity log if everything was successful...otherwise empty string
   *
   */

   usdCreateActivityLog: function(handle, message, login){
      if(!login){
         this.log("Calling USD createActivityLog -- attempting to reuse a previous SID token");
         login = false;
      } else {
         this.log("Calling USD createActivityLog -- forcing a login first");
      }
      if(login){
         var sid = this.usdLogin();
      } else {
         sid = gs.getProperty("com.snc.integration.usd.sid","");
      }
     
      if(sid != ""){
         
         var s = new SOAPMessage('CA Service Desk', 'createActivityLog');
         s.setParameter('description', message);
         s.setParameter('timeSpent', '0');
         s.setParameter('logType', 'LOG');
         s.setParameter('internal', 'False');
         s.setParameter('sid', sid);
         s.setParameter('objectHandle', handle);
         s.setParameter('creator', 'cnt:65A118F08AB7824F82E88534C0613BEE');
         s.post();
         var obj = this.getResponse(s);
         if(this.logLevel >= 3){
           JSUtil.logObject(obj);
         }

       
         if( obj['soapenv:Body'] && obj['soapenv:Body'].createActivityLogResponse && obj['soapenv:Body'].createActivityLogResponse.createActivityLogReturn && obj['soapenv:Body'].createActivityLogResponse.createActivityLogReturn.UDSObject){
            var udsObject = obj['soapenv:Body'].createActivityLogResponse.createActivityLogReturn.UDSObject;
            if(udsObject.Handle){
               return udsObject.Handle;
            }
         }
      }
     
      if( sid == "" || (login==false && this.usdCheckForLoginError(obj))){
         return this.usdCreateActivityLog(handle, message, true);
      }
    return "";
   },
   

   getResponse: function (s,xml){
    if(!xml && xml!=false){
     xml = true;
    }
      var k = 1;
      var r = s.getResponse();
      while(r == null) {
         this.log("waiting ... " + k + " seconds");
         r = s.getResponse(1000);
         k++;
         
         if (k > 330) {
            this.log("ERROR: Never got a response from web service call through MID Server", 0);
            break; // service did not respond after 30 tries
         }
      }
    if(xml){
     this.log("Got Response of : " +r);
     r = this.usdRemoveExtraXmlDef(r);
     this.log("Going to call helper");
     var helper = new XMLHelper(r);
     this.log("Helper: " + helper);
     var obj = helper.toObject();
    } else {
       obj = r;
    }
      this.log("OBJ: " + obj);
      return obj;
     
     
   },

   usdCheckForLoginError: function(obj){
    this.log("SOAP BODY? " + obj['soapenv:Body']);
    this.log("SOAP Fault? " + obj['soapenv:Body']['soapenv:Fault']);
    this.log("SOAP Fault Detail? " + obj['soapenv:Body']['soapenv:Fault'].detail);
   
      if( obj['soapenv:Body'] && obj['soapenv:Body']['soapenv:Fault'] && obj['soapenv:Body']['soapenv:Fault']){
         var fault = obj['soapenv:Body']['soapenv:Fault'].detail;
         this.log("FAULT ERROR CODE: " + fault.ErrorCode);
         if(fault.ErrorCode == "1010"){
            return true;
         }
      }
      return false;
   },
   


   log:function(msg, level){
      if(!level){ level=3 };
       
      if( level <= this.logLevel ){
         gs.log(msg, this.logSource);
      }
   },
   
   type: 'CASDHelper'
}

The Library in Action – Scripting with the library

Here are some coding examples using the library above:

1
2
3
4
5
6
7
8
9
gs.log("I started the query!");
var a = new CASDHelper();

//Query with Select Command - library will automatically authenticate if necessary
var ticket = a.usdDoSelect("cr", "ref_num = '"+current.u_handle+"'", 1000, ["description","affected_resource", "persistent_id"]);

gs.log("Description: " + ticket.Attributes.Attribute[0].AttrValue);
gs.log("Affected Resource: " + ticket.Attributes.Attribute[1].AttrValue);
gs.log("Persistent ID: " + ticket.Attributes.Attribute[2].AttrValue);