- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on ‎04-29-2015 12:33 AM
I would like to start off by thanking my fellow community members and stackoverflow.com who have been my reference in building these two scripts.
This integration is built through REST API calls.
- You will need to create an account in Airwatch and allow it API access. You will also need your Airwatch tenant code as it will be an HTTP header in your rest call.
- Build a basic REST Outbound call.
- Set your HTTP headers of aw-tenant-code="your_AW_Tenant_code", Accept=application/json, and Content-Type=application/json.
- These integrations only use the "get" Method.
- For the script to pull the full CMDB of only iPhones use the endpoint: https://<Your_company>.airwatchportals.com/API/v1/mdm/devices/search?model=iPhone
-you can replace iPhone with any other value that matches the model of the device, or remove "model=iPhone" for a full inventory. - For the script to pull a specific record from a UI Action use the endpoint:
https://<Your_company>.airwatchportals.com/api/v1/mdm/devices/serialnumber/${SerialNumber}
-the script will provide the open record's serial number to Airwatch to collect the data for that device. - You will need a new inbound Web Service to send the data to. This Web service should contains the fields you are interested in from Airwatch.
(Run the test from the REST call to receive a sample of what fields and data are brought over.) - The Web Service will also need a transform map to map those fields to the actual CMDB table you want the devices in. Make sure you coalesce on a unique fields like serial number.
- I have made a Mobile Devices table which extends the table Hardware and added all the Airwatch fields. From it I created 3 more, iPhones, iPads, and Androids. And as such have three Web Services to map each to their table.
Below are two scripts, one to pull only one device using its serial number, and the other to run the full iPhone pull.
Airwatch pull using UI action for single device:
try {
//Initiate REST call and provide this record's serial number
var r = new sn_ws.RESTMessageV2('AW CI Query', 'get');
r.setStringParameter('SerialNumber', current.serial_number);
var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
//Logging or clowns will eat me
gs.log("REST Call, AW iPhone Pull for " + current.serial_number + " terminated with: " + httpStatus);
/*Uncomment for debugging
gs.log("REST Call, AW pull from CI, has a body of:\n" + responseBody);
*/
//Parse the JSON body returned by AW
var parsed_object = JSON.parse(responseBody);
//create glide records to import table
var gr = new GlideRecord('u_iphone_pull');
gr.initialize();
//Map JSON fields to import table fields
gr.u_assetnumber = parsed_object.AssetNumber;
gr.u_compliancestatus = parsed_object.ComplianceStatus;
gr.u_compliancesummary = parsed_object.ComplianceSummary;
gr.u_compromisedstatus = parsed_object.CompromisedStatus;
gr.u_devicefriendlyname = parsed_object.DeviceFriendlyName;
gr.u_enrollmentstatus = parsed_object.EnrollmentStatus;
gr.u_imei = parsed_object.Imei;
gr.u_isremotemanagementenabled = parsed_object.IsRemoteManagementEnabled;
gr.u_issupervised = parsed_object.IsSupervised;
gr.u_lastcompliancecheckon = parsed_object.LastComplianceCheckOn;
gr.u_lastcompromisedcheckon = parsed_object.LastCompromisedCheckOn;
gr.u_lastenrolledon = parsed_object.LastEnrolledOn;
gr.u_lastseen = parsed_object.LastSeen;
gr.u_locationgroupname = parsed_object.LocationGroupName;
gr.u_macaddress = parsed_object.MacAddress;
gr.u_model = parsed_object.Model;
gr.u_operatingsystem = parsed_object.OperatingSystem;
gr.u_ownership = parsed_object.Ownership;
gr.u_phonenumber = parsed_object.PhoneNumber;
gr.u_platform = parsed_object.Platform;
gr.u_serialnumber = parsed_object.SerialNumber;
gr.u_udid = parsed_object.Udid;
gr.u_useremailaddress = parsed_object.UserEmailAddress;
gr.u_username = parsed_object.UserName;
/*Uncomment for debugging
gs.log("Serial being sent to the map: " + parsed_object.SerialNumber);
*/
//GFABS!
gr.insert();
}
catch(ex) {
var message = ex.getMessage();
}
Airwatch full pull parsing through JSON array:
try {
// Call the REST Message
var r = new RESTMessage('AW iPhone Pull', 'get');
var response = r.execute();
var responseBody = response.getBody();
gs.log("REST Call success");
//Parsing the Response
var parser = new JSONParser();
var parsed = parser.parse(responseBody);
//Parse based on the array object named Devices and save to variable "cmdb"
var cmdb = parsed["Devices"];
//Loop through the array
for (var key in cmdb) {
if (cmdb.hasOwnProperty(key)){
var parsed_object = cmdb[key];
//Create a new record on each loop
var gr = new GlideRecord('u_iphone_pull');
gr.initialize();
//Map JSON fields to web service table fields
gr.u_assetnumber = parsed_object.AssetNumber;
gr.u_compliancestatus = parsed_object.ComplianceStatus;
gr.u_compliancesummary = parsed_object.ComplianceSummary;
gr.u_compromisedstatus = parsed_object.CompromisedStatus;
gr.u_devicefriendlyname = parsed_object.DeviceFriendlyName;
gr.u_enrollmentstatus = parsed_object.EnrollmentStatus;
gr.u_imei = parsed_object.Imei;
gr.u_isremotemanagementenabled = parsed_object.IsRemoteManagementEnabled;
gr.u_issupervised = parsed_object.IsSupervised;
gr.u_lastcompliancecheckon = parsed_object.LastComplianceCheckOn;
gr.u_lastcompromisedcheckon = parsed_object.LastCompromisedCheckOn;
gr.u_lastenrolledon = parsed_object.LastEnrolledOn;
gr.u_lastseen = parsed_object.LastSeen;
gr.u_locationgroupname = parsed_object.LocationGroupName;
gr.u_macaddress = parsed_object.MacAddress;
gr.u_model = parsed_object.Model;
gr.u_operatingsystem = parsed_object.OperatingSystem;
gr.u_ownership = parsed_object.Ownership;
gr.u_phonenumber = parsed_object.PhoneNumber;
gr.u_platform = parsed_object.Platform;
gr.u_serialnumber = parsed_object.SerialNumber;
gr.u_udid = parsed_object.Udid;
gr.u_useremailaddress = parsed_object.UserEmailAddress;
gr.u_username = parsed_object.UserName;
/*Uncomment for debugging
gs.log("Serial being sent to the map: " + parsed_object.SerialNumber);
*/
//GFABS!
gr.insert();
}
}
catch(ex) {
var message = ex.getMessage();
}
I hope this allows you to build a basic Airwatch integration. And hopefully provide a good understanding on how to pull data in to SNow via REST.
- 14,070 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Carlos,
Thanks a lot for this info! Where do I get the tenant code from? I've been wandering around the console for a while and can't find it anywhere.
Regards,
Geoffrey
EDIT: I figured it out. It's the API Key, at Settings > System > Advanced > API > REST API. Not putting it in returns an authentication error, just FYI.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hello Geoffrey,
I acquired the tenant code from our AW engineer. If it is not on your console i would suggest contacting support. I do believe they call it an "API key".
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Carlos,
I have the web service call working, and I'm now pulling device data from AirWatch into ServiceNow. But I've noticed that it's only retrieving 500 devices (out of about 1,800). Did you encounter this? Do you know how to increase (or remove) this limit?
Regards,
Geoffrey
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
As a matter of fact i did run in to that afterwards. I don't know if it is a limitation on the AW side or the SNC REST call, but what i did was modify the address and add a variable after looking at the help section on the AW API page.
Original address to pull all iPhones:
https://<your AW portal>/API/v1/mdm/devices/search?model=iPhone
Modified address to download 400 at a time:
https://<your AW portal>/API/v1/mdm/devices/search?model=iPad&pagesize=400&page=${PageNumber}
Then on your scheduled job(s) just add the code:
var r = new sn_ws.RESTMessageV2('Your AW REST call', 'get');
r.setStringParameter('PageNumber', '0'); // Here increment the zero per schedule
var response = r.execute();
AW REST Help link:
https://<your AW portal>/API/help
Navigate to this link on a browser, log in, and you will find great documentation on how to interact with their REST API. It is actually better documented here than on the PDF.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Just to clarify after reading my reply. In the modified address:
search? is the API method to search through the database with specified criteria
model= search for records containing the mentioned text (i don't know how it deals with spaces)
pagesize= how many records to return per page/query
page= what page to bring back
Therefore I now have 3 scheduled jobs that bring back page 0, 1, and 2 since we have less than 1200 records. 1 record is 1 device.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thanks, Carlos. Champion!
I just set the pagesize to 3000 and it works perfectly.
https://<your AW portal>/API/v1/mdm/devices/search?pagesize=3000
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Awesome!
That means the 500 limit is being set on the AW side.
What I have done now to keep it as one job is create a while loop with a break.
I have an infinite loop at the top:
while (pages > 0) {...the script}
but after the rest call i have a check against the HTTP status returned from the rest call.
if (response.getStatusCode() != 200) break;
This allows me to increment the page number within the loop:
pageNum++;
So now i have one job, downloading 400 records at a time until there are no more records, then it stops because no records returns a different HTTP status .
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I am attempting to do this and have received a responseBody value from AirWatch, with the records I expect; however it seems that the full script above always returns false at the "if(cmdb.hasOwnProperty(key))" check. Any clue as to why this is returning false? The objects are in the array as I believe they should be.
Are you still using this integration?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I removed that if check and it seems to work now.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hello Mike,
I am still using this script for our AW download. The "if" statement is still working for me.
I am on Fuji Patch 5 and ruining well. We started with Calg.
Are you on Fuji?
And if you are did you start with Fuji?
It may be due to the upgrades that i have something that is allowing it to work.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
It is for a client and they are on Eureka Patch 11.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Interesting, well as long as it is working for you .
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Carlos,
I want to perform enterprise wipe/device wipe out.
Initially I was trying to test in airwatch itself but it was not working.
We are using airwatch Rest API for device wipe/enterprise wipe URL but it was showing access denied after host .
We are trying to test in Rest Client Chrome Plugin.
1. Enterprise Wipe-
Functionality- Enterprise wipes/unenrolls a device.
Method- POST.
API URL- https://host/API/v1/mdm/devices/{DeviceID}/enterprisewipe.
2. Device Wipe-
Functionality- Sends a device wipe command to the device.
Method- POST.
API URL- https://host/API/v1/mdm/devices/{DeviceID}/devicewipe.
To access REST API functionality following steps need to be followed-
Please help me out
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hello Sagar,
For my access i had our AirWatch admin grant my service account API access.
My recommendation to you is to download the AirWatch REST API document, in the first couple of chapters it explains what permissions are required within AirWatch and how to configure them. Also make sure you add your personal tenant code as an HTML header as explained in the AirWatch API doc and on the top of my post.
The user also needs to have the ability to wipe phones over the UI, if all the AirWatch admin gave you was read only, then you will not be able to execute against a mobile device.
I would recommend starting with something less destructive also, see if you can push an app to mobile device first and then delete the app.
I hope this helps.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
thanks Carlos for your reply.
i have followed all the steps mentioned in api document and still i am getting Status:307: Temporary Redirect after https://host/API/v1 .
Getting access denied after this https://host/API/v1/mdm/devices/{DeviceID}/enterprisewipe.
please help me our what can we do
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hello Sagar,
From here i would recommend contacting your AirWatch support team.
An HTTP 307 means the request should be repeated with another URI. The documentation does not specify a need to redirect.
Work with your support team and have them verify credentials, permissions, and your REST message format.
Make sure you are replacing {DeviceID} with a valid MAC address, Serial Number, or UUID.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
All is upto mark but still showing access denied after v1
On 24-May-2016 11:35 pm, "phoenix516" <community-no-reply@servicenow.com>
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
All is upto mark but still showing access denied after v1
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Carlos I am able to perform wipeout from airwatch console through API Client,now could you please help me how can we integrate to Servicenow
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Carlos,
Is there anyway to pull only the devices, that are updated/changed after the last pull ( or say in some specific duration). Asking this because, the AirWatch pull is one of the slow running jobs in our instance, and i believe its better to pull only the delta rather than the entire set.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Only if their API has reticently changed. The call I use is for a dump of everything and I reconcile on the ServiceNow side.
If all you wanted was only new devices to AW you may be able to do an encoded query for all devices that are not {insert list of existing serial numbers}.
Problem is that if something changed on an existing device you would not see the change.
Also, i am not sure if their API even supports an encoded query like this.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Carlos,
Thanks for your insight, i do need to changes on the existing devices, so i cannot go with the serial number idea.
As much as i saw in the API, the 2 date parameters specified for device search, are 'lastseen' and 'seensince', and these wouldn't serve my purpose .
I am going to look further, to see if its possible with joining the other web services available.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
What can be the maximum value of "pagesize"?
Thanks,
Pragya
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Carlos, I am working in the same integration rigth now, may i know how did you create the script?
Thanks in advance
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I honestly do not know, it depends on how many devices is in your Ariwatch database.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I dont seem to be using it anymore....
//Parsing the Response
var parser = new JSONParser();
var parsed = parser.parse(responseBody);
//Parse based on the array object named Devices and save to array "cmdb"
var cmdb = parsed["Devices"];
//Lopp through the new array made from parsing JSON data and inject to WS table
for(var i=0; i<cmdb.length; i++){
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Phoenix, I really need your help, I am trying to use the below scheduled script to put the AW devices into my cmdb class but it seems that it is not working, the Get Method is working but no able to put the data into cmdb table, any advice will be appreciated
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
How i created the script? I had an idea, i used the ServiceNow documentation to build the REST call, then W3Schools and much, much, much google.com to find the code to parse the data, iterate through the nodes, and populate the table.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
So i see you are using "parsed_object" to represent the key of each Device Node, i dont how ever see you matching that with the "i" in the for loop.
The variable "i" created and used in the for loop is used to let the rest of script know which node you are talking about. So when the loop is at node 1 and you call variable[1] it knows which you are talking about.I have never used variable[key] to represent the node i am working on.
Here is what i have implemented right now and is working....
//Parsing the Response
var parser = new JSONParser();
var parsed = parser.parse(responseBody);
//Parse based on the array object named Devices and save to array "cmdb"
var cmdb = parsed["Devices"];
//Lopp through the new array made from parsing JSON data and inject to WS table
for(var i=0; i<cmdb.length; i++){
//Create a new record on each loop
var gr = new GlideRecord('u_airwatch_download');
gr.initialize();
//gs.log("in the loop in the new glide record");
//Map JSON fields to web service table fields
gr.u_assetnumber = cmdb[i].AssetNumber;
gr.u_compliancestatus = cmdb[i].ComplianceStatus;
gr.u_compliancesummary = cmdb[i].ComplianceSummary;
gr.u_compromisedstatus = cmdb[i].CompromisedStatus;
gr.u_devicefriendlyname = cmdb[i].DeviceFriendlyName;
gr.u_enrollmentstatus = cmdb[i].EnrollmentStatus;
gr.u_imei = cmdb[i].Imei;
//< Many more fileds below trimmed>
//GFABS!
gr.insert();
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Also, notice i am not importing directly to the mobile devices table, i am importing this to an inbound web service endpoint so i can place a transform map in between to massage the data and coalesce against the serial #.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hello phoenix516, very interesting.
How many full days approximately did you invest in building and testing these two scripts?
Thank you!
Ignacio.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Carlos,
Do we need the username/password combo for authentication to Airwatch or Is the API key(tenant key) only required for the necessary authentication?
Regards,
Harminder
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi phoenix,
Not sure if it has been spotted... but you do not close your if statement in the script to get all AirWatch devices.
if (cmdb.hasOwnProperty(key)){ // Open curly brace, no close
var parsed_object = cmdb[key];
This raises a syntax error 'Unexpected end of input'.
FIX
if (cmdb.hasOwnProperty(key)) {
var parsed_object = cmdb[key];
} // <-- FIX
Or use this
if (cmdb.hasOwnProperty(key)) // <-- FIX, no curly brace is needed
var parsed_object = cmdb[key];
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Phoenix,
Is it possible to pull out the lifecycle reporting from Airwatch to SNOW ?
If yes, can you please share the syntax or script.
Thanks
PV
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hello Prapula,
I honestly do not know. I have not tried it. I would recommend checking the Airwatch API guide and see if there are any REST API calls that can be made for that.
This integration i built years ago was strictly for pulling the AW inventory in to our CMDB.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Tenant is requires in the HTTP headers if i remember correctly.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I do not think i spotted that, thanks. I must have fixed it when i put this in production years ago and not placed that code in here.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Is this still a valid solution to an Airwatch integration?
has anyone recently used this to integrate with Airwatch?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Question, Once a device has been deleted on the Airwatch side, How can we reflect this change on the serviceNow side?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi,
It seems that you have created some staging tables to set the data from Airwatch.
I am wondering whether I could use import set tables instead of custom staging tables.
Do you know any limitation or any consideration on this?
Best Regards,
Kohei