Deleting Unenrolled Devices via the AirWatch API



We’ve started to look at enabling “Compliance Policies” within AirWatch.

However, these are scoped to “Assignment Groups” (was “Smart Groups”, another thing that seems to be mid-rename) & “Assignment Groups” do not have criteria for a devices “Enrolment Status”.

Below is an API script that I am using to automate device deletion if a device meets certain conditions & the method to the madness.

Deleting Devices??

As mentioned above, “Assignment Groups” do not have criteria for a devices “Enrolment Status” this means that devices that have an enrolment status of “Device Wipe Pending”, “Enterprise Wipe Pending” or “Enrollment In Progress” will fall under the “Compliance Policies” with potential alerts going to users for devices no longer in use.

I have put in a Feature Request for this, here.

Enrollment In Progress

We’ve found a few devices with a stuck/aborted enrolment state, which shows in the console as “Enrollment In  Progress”

These devices never complete the enrolment, but will use a license if reporting back into AirWatch within 30 days.

Wipe Pending

I’ve been advised by AirWatch support that it’s safe to delete a device from the console once a wipe command is issued, as this command will be completed when (if) the device next reports into AirWatch.


If you’re running a BYOD scheme, people will be enrolling & unenrolling as they want/need (need being if a device is lost/stolen, irreparably damaged, replaced or sold on & wiped before).

We have found that, & as such one of the “Compliance Policies” we’re looking into is to email an “Employee Owned” devices enrolled user if a device has not been seen for 30 days, asking them to check in or issue an “Enterprise Wipe” via the Self Service Portal.

This will escalate & lead to an “Enterprise Wipe” after so many days, but then we’d still have the old records in AirWatch.

This script would then delete the un-needed devices from the console, but you can amend the “Ownership” type as needed.


The script is based off of the template shown in the previous post, as such I’m going to skip over the already documented variables

The below variables are in addition to those from the template.


SUPPLY: This variable can be set to the below to limit the API calls to only look for devices of a certain ownership type. If this is not wanted you can remove this as mentioned later.

Ownership levels:

  • E = Employee Owned
  • C = Corporate Dedicated
  • S = Corporate Shared


SUPPLY: API calls via Location Group ID work in a waterfall method, so if you specify the root Organisation Groups Location Group ID then the call will contain all devices within the instance.

If you choose a child Organisation Group with other Organisation Groups underneath, then the call will contain all devices from that child Organisation Group down, including it’s own child Organisation Groups.

To get the Organisation Groups Location Group ID see this post.

As with the “ownershipLevel” variable, you can remove this if not needed as mentioned later.


GENERATED: This is a empty list used later within the script.

Script Breakdown

Again the script is based off of the template shown in the previous post, as such I’m going to skip over the already documented function sendMail.

Trying to make the API call

After the variable declaration & the sendMail function there is a try block where we try to make the API call.

awTest = requests.get

This searches AirWatch for all devices found under a certain Organisation Group (as per it’s locationGroupID) with an Ownership level (as per ownershipLevel).

This uses the API get call: “Search Device Details” which allows for granular search terms as per:

https://host/API/v1/mdm/devices/search?user={user}&model={model}&platform={platform}&lastseen= {lastseen}&ownership={ownership}&lgid={lgid}&compliantstatus={compliantstatus}&seensince={seensince}&page={page}&pagesize={pagesize}&orderby={orderby}&sortorder={sortorder}

If you’re not interested in limiting the searches to a Organisation Group or with an Ownership level you can amend the call as per the above search terms.

If this GET request fails, the script exits & emails the contents of the log.

deviceDetails = deviceDetails[‘Devices’]

For each device found, we next get the This will set the deviceDetails variable to only contain the data from within ‘Devices’ list within the json.

for device in deviceDetails

Next we check the value of the ‘EnrollmentStatus’ key within each device within the deviceDetails list, if this is not ‘Enrolled’ then we grab the devices AirWatch Id, Serial Number, Enrolment Status, Friendly Name & when it was last seen.

These are then added to deleteDeviceList & written to the scripts log.

deviceID = str(device[0])

As the returned value for device[0] is an integer, we need to convert it to a string for concatenation within the API URL.


This second declaration is included as it resets the deleteDeviceList to an empty list, for safe running when testing this script.

This will give some output like the below, when all the supplied variable values for your environment are added to the script:

2015-12-15 08:52:46,108 INFO -------- Started Checking for Employee Owned Devices to Delete --------
2015-12-15 08:52:46,116 INFO Starting new HTTPS connection (1):
2015-12-15 08:52:48,925 DEBUG "GET /API/v1/mdm/devices/search?ownership=E&lgid=18694&pagesize=10000 HTTP/1.1" 200 701957
2015-12-15 08:52:50,643 INFO [313944, u'', u'EnrollmentInProgress', u'NOKIA RM-914_eu_euro1_111-11111ad1c111b1b1bc1d11b', u'JBloggs', u'2015-11-01T16:56:03.457']
2015-12-15 08:52:50,644 INFO -------- No Devices to be deleted --------

Once you’re happy with the scripts returned data, you can comment out the deleteDeviceList = [] declaration.

if not len(deleteDeviceList):

If the deleteDeviceList has no entries, then update the statusMessage & then go to the sendMail function & exit the script.


If deleteDeviceList has entries then log the about of devices to be deleted.

for device in deleteDeviceList:

For each entry in deleteDeviceList, set deviceID to the entries “Id” value.

The “Id” of an object is a unique identifier used within AirWatch & so is a what we want to use when targeting deleting an object.

deleteDevice = requests.delete

Within this try block we try & delete the device with the “Id” given,

Successful deletions are written to the scripts logs, any errors & the error is passed to the sendMail function & the script quits.


Lastly, if we’ve successfully deleted some devices. Then the number of devices is passed with a message to the sendMail function & the script quits.

The Script

Below is the script itself & as mentioned this script will run as with the variable values supplied & it will merely advise what devices fit under the criteria you decide.

To start deleting devices, comment out the second declaration of deleteDeviceList, & as the usual caveats apply (maybe even more so as we’re deleting devices).

6 thoughts on “Deleting Unenrolled Devices via the AirWatch API

  1. jafullersr

    Hi macmule, the feature request link to AirWatch’s Support site isn’t working. I’d like to try to add to your feature request. Thanks!

  2. ramkumar nagaraj

    dear sir, i did not undrestand which part needs to be commented out in the code
    pls guide me

  3. Oliver

    With regard to “I’ve been advised by AirWatch support that it’s safe to delete a device from the console once a wipe command is issued, as this command will be completed when (if) the device next reports into AirWatch.”

    The documentation seems to suggest otherwise. states, “When the Delete Device command has been completely processed, all commands associated with that DeviceID are purged from the AirWatch DB, including the Enterprise Wipe Command tied to that device’s DeviceID. Therefore, if the Delete Device operation is performed on a device that is turned off/disconnected from the network, it will not receive the Enterprise Wipe Command issued by the console immediately upon the Delete Device command.”

    Ideally the Delete Device command would not be “completely processed” until any pending wipe commands were completed, or there would be an option to allow for this behaviour, but it does not sound like this is currently the case.

    • Hi Olivier,

      Might well be the case now, but this blog post was posted 15/12/2015 and pre the VMWare acquisition of Airwatch.

      Things may well have changed since 🙂

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.