JSS PUT API using Curl Help

Bobst
New Contributor

We are trying to enroll 400 iPads with the XML template from JSS/Resource/mobiledevices/id from the API. We have created a script that reads all the data and creates the new XML record for each of the iPads. Having trouble with JSS PUT using curl. In this example "/CO-TEST-79714.xml" is what was created from the script. It contains all the same data that mobiledevices/id has, we are just inputting some of the details to enroll the iPad.

Any help with the curl command would be appreciated.

curl -X PUT -H "Accept: application/xml" -H "Content-type: application/xml" -s -k -u username:password -d "/CasperImports/CO-TEST-79714.xml" "https://yourJss.com:8443/JSSResource/mobiledevices/id/2534"

18 REPLIES 18

Josh_S
Contributor III

I use the API a lot. The first thing I noticed is that you have an extra header from what I generally use. The "Accept: application/xml" header isn't needed. But, an extra header shouldn't cause any issues. The root of the issue seems to be your data source. By default, -d indicates that you want to send the specified data. In this case, "/CasperImports/CO-TEST-79714.xml". That exact string is the data you're sending, not the data contained in that file at that path.

If you want to send the data stored in the file, you need to prepend an "@". So your curl command should look like:

curl -X PUT -H "Content-Type: application/xml" -s -k -u username:password -d "@/CasperImports/CO-TEST-79714.xml" "https://yourJss.com:8443/JSSResource/mobiledevices/id/2534"

Hope this helps!

Bobst
New Contributor

Thanks for the post, that was definitely causing my issue for the most part. I modified my curl command following your example but, getting another error message. I have limited knowledge of API, especially pushing XML files to it.

Here is what I'm getting.

<html><head><title>411 Invalid Request</title></head><body>Invalid Request: ??</body>

I just made sure that my user has access to the API.

Any thoughts?

mm2270
Legendary Contributor III

The API user account needs to have write (Update) privileges to the API objects you're trying to update, not just read access. I would double check how the API account is set up.
But, generally we don't see 'Invalid Request' returned when there's an authentication issue, so that may or may not actually be the problem.

If the account is set up correctly and you're still seeing this, you can also try swapping out the -d for -T and placing the path to the xml file for upload after it, so instead of -d @/path/to/yourxml.xml, try -T /path/to/yourxml.xml and see if that works any differently.

Bobst
New Contributor

Thanks for you input but, I had no luck with -T reported same error.

The only other thing I can think of is the fact that I'm pushing in blank data through the XML file?

mm2270
Legendary Contributor III

Blank data? Can you elaborate on what you mean by that? Also, are you confirming that the xml file is validly formatted? The API will not accept anything that is malformed.

gachowski
Valued Contributor II

Hey I am the worlds worst script guy and it took me days to figure out how to delete machines with the API. I found that I had to use c shell to get it to work.... for some reason bash didn't ....

C

Bobst
New Contributor

So we are not using every piece of data in the XML template for creating new records in Casper. We are using things like, Display Name, Serial Number, Asset Tag, and email address, the rest of the data is escaped and empty.

We copied the XML template from the API. So I would hope that it is exactly what we need.

Josh_S
Contributor III

If you're attempting to create new records, you should be specifying an id of zero ("0") and be using "POST" and not "PUT". PUT is used to update an existing record. If you're using an empty xml to create a new mobile device, you might also be running into an issue about minimum information required. You're basically enrolling a device when you attempt to create a new one. There might be some minimum information required in this case, UDID/Serial/MAC?

Bobst
New Contributor

Thanks Josh_S, I think that might be my problem. I did modify the PUT to a POST. Need to add some more information to my file and see if it will accept it then.

Is there any way to tell the minimum information?

Josh_S
Contributor III

No way that I know of. There might not even be any minimums, I was just guessing. I've never tried to enroll a device using the API, only modify existing devices.

Bobst
New Contributor

I tried to add more data. Still having problems creating records, not sure where the issue is. I was able to easily modify current records no problem. I'll keep at it and post if I figure it out.

mm2270
Legendary Contributor III

Can you possibly supply an example of the xml file you are using to do the POST, maybe with sensitive information replaced or blanked out? I think being able to see how the xml is structured may help solve where the issue is.

Also, I assume you checked the API account to make sure it has privileges to create the new objects you want? I know before I mentioned "Update", but that was because I didn't read carefully and see that you were trying to create new items. They are two different columns of privileges for an API account.

dwandro92
Contributor III

@Bobst

In regards to the minimum information, I can tell you that I use an in-house "pre-imaging wizard" utility to create/update computers in the JSS prior to imaging, and I only upload the following info:

  1. Hardware UDID
  2. Serial Number
  3. Computer Name

I also populate a couple of other fields (asset tag, building, department), but these fields are definitely not required and are only populated so that devices fall into my smart groups which are used during imaging.

This is what my XML data looks like:

<computer>
   <general>
      <name>$pcName</name>
      <serial_number>$hwSerial</serial_number>
      <udid>$hwUDID</udid>
      <asset_tag>$assetTag</asset_tag>
   </general>
   <location>
      <username>$userID</username>
      <department>$departmentName</department>
      <building>$buildingName</building>
   </location>
</computer>

Bobst
New Contributor

Here is the command that I'm using
curl -sfku $apiUser:$apiPass -T /Users/$HOME_DIRECTORY/Desktop/CasperImports/mobile.xml -X POST --url https://yourJSS.net:8443/JSSResource/mobiledevices/id/0

If you remove the -s you will see it's getting a 500 error.

Here is the sample XML File.

<mobile_device> <general> <id<name/>$ID</id> <display_name>$NAME</display_name> <device_name>$NAME</device_name> <name>$NAME</name> <asset_tag>$AssetTag</asset_tag> <last_inventory_update/> <last_inventory_update_epoch/> <last_inventory_update_utc/> <capacity/> <capacity_mb/> <available/> <available_mb/> <percentage_used/> <os_type/> <os_version/> <os_build/> <serial_number>$SerialNumber</serial_number> <udid>$UUID</udid> <initial_entry_date_epoch/> <initial_entry_date_utc/> <phone_number/> <ip_address/> <wifi_mac_address>$WIFI_MAC_ADDERSS</wifi_mac_address> <bluetooth_mac_address/> <modem_firmware/> <model/> <model_identifier/> <modelDisplay deprecated="9.4"/> <model_display/> <device_ownership_level/> <managed/> <supervised>true</supervised> <tethered/> <battery_level/> <airplay_password/> <device_id/> <locales/> <do_not_disturb_enabled>false</do_not_disturb_enabled> <cloud_backup_enabled>false</cloud_backup_enabled> <last_cloud_backup_date_epoch>0</last_cloud_backup_date_epoch> <last_cloud_backup_date_utc/> <itunes_store_account_is_active/> <computer> <id>-1</id> </computer> <last_backup_time_epoch/> <last_backup_time_utc/> <site> <id>-1</id> <name>None</name> </site> </general> <location> <username/> <real_name/> <email_address/> <position/> <phone/> <department>$Department</department> <building>$Building</building> <room/> </location> <purchasing> <is_purchased/> <is_leased>false</is_leased> <po_number/> <vendor/> <applecare_id/> <purchase_price/> <purchasing_account/> <po_date>2015-06-15</po_date> <po_date_epoch/> <po_date_utc/> <warranty_expires/> <warranty_expires_epoch/> <warranty_expires_utc/> <lease_expires/> <lease_expires_epoch>0</lease_expires_epoch> <lease_expires_utc/> <life_expectancy>0</life_expectancy> <purchasing_contact/> <attachments/> </purchasing> <applications/> <security> <data_protection/> <block_level_encryption_capable/> <file_level_encryption_capable/> <passcode_present/> <passcode_compliant/> <passcode_compliant_with_profile/> </security> <network> <home_carrier_network/> <cellular_technology>None</cellular_technology> <voice_roaming_enabled/> <imei/> <iccid/> <current_carrier_network/> <carrier_settings_version/> <current_mobile_country_code/> <current_mobile_network_code/> <home_mobile_country_code/> <home_mobile_network_code/> <data_roaming_enabled/> <roaming/> </network> <certificates> <size>1</size> <certificate> <common_name/> <identity/> </certificate> </certificates> <configuration_profiles/> <provisioning_profiles> <size>0</size> </provisioning_profiles> <mobile_device_groups/> <extension_attributes/>
</mobile_device>

Josh_S
Contributor III

@Bobst That would do it. That xml is not well formed, and you're specifying an $ID for a new record. You also do not have to include empty tags, which might help reduce the clutter and make it easier to pinpoint errors. There's a couple misspellings in your variable names too, WIFI_MAC_ADDERSS. If it's misspelled, it doesn't matter as long as you're consistent. I would copy/paste to help make sure you're consistent with everything. And I wouldn't bother specifying values which are gathered during the recon process.

Last thing, bash variable values are not interpreted by curl prior to uploading. If you want them interpreted, you will have to "echo" or "printf" this string to a file, mobile.xml, which you then upload via curl. You could alternately specify the whole thing as data to be passed without writing it to a file first.

Try this, you don't need the indentations or the line breaks but it makes it much easier to read and find errors with unbalanced elements:

<?xml version="1.0" encoding="UTF-8"?>
<mobile_device>
  <general>
    <display_name>$NAME</display_name>
    <device_name>$NAME</device_name>
    <name>$NAME</name>
    <asset_tag>$AssetTag</asset_tag>
    <serial_number>$SerialNumber</serial_number>
    <udid>$UUID</udid>
    <wifi_mac_address>$WIFI_MAC_ADDERSS</wifi_mac_address>
  </general>
  <location>
    <department>$Department</department>
    <building>$Building</building>
  </location>
  <purchasing>
    <is_purchased>true</is_purchased>
    <is_leased>false</is_leased>
    <po_date>2015-06-15</po_date>
  </purchasing>
</mobile_device>

mm2270
Legendary Contributor III

Agreed 100% with @Josh_S Your xml has much too many tags in it that aren't necessary. If you are not specifying any values, its better to just leave them out entirely than to include blank tags. A general good rule here when trying to POST a new record is to only include what's necessary for the JSS to create the record and leave everything else out, especially when they are items that will just get populated automatically when the device gets enrolled and submits inventory. But you do need to make sure the xml has all the proper opening and closing tags throughout it, or balanced, as Josh put it.

Bobst
New Contributor

Thanks guys, I will modify my XML files and double check variable names. I also didn't know that about Curl. Thanks again. I will post again once I reform some of the file and my script.

Bobst
New Contributor

Okay thanks for all the help I was finally able to figure out my problem.

Here is the script that I made and tied it to an automator app. The Automator App reads in a CSV file with the data that you wanna import. For example Name, Asset Tag, Serial, UDID and email address. So you could take this CSV file and create multiple lines with the varied data that you want and drop it on the automator app. The automator add generates multiple files to the projected output path. After each file creation it curls the data up either using the POST or PUT commands. So if you are in my shoes and have 400 iPads that you need to enroll just gather all the necessary data and drop the CSV file and the automator app will do everything else. Hope this helps someone else.

The CSV is comma separated. Also for mobile devices the UDID is required and it told me after i left it out.
<p>Error: Mobile device UDID is required</p>

!/bin/sh

Created By: Dublin City Schools IT Department, thanks to JAMFNation Forums.
6/19/15
Generates an XML File for easy upload through API using curl

jssAPIUsername=""
jssAPIPassword=""
jssAddress="https://yourjss.com:8443"**

IFS=","
DESTIN_FOLDER="$HOME/Desktop/CasperImports"

if [ "$#" -eq 0 ];then echo "Error: You most drop a csv file onto this application in order to work properly!!!" exit 1
fi

if [ ! -d "DESTIN_FOLDER" ]; then mkdir $DESTIN_FOLDER
fi

cat $1 | while read DISPLAY_NAME ASSET_TAG SERIAL_NUMBER DEPARTMENT BUILDING USER_NAME EMAIL_ADDRESS
do

cat <<EOF > "$DESTIN_FOLDER/$DISPLAY_NAME.xml"
<mobile_device> <general> <display_name>${DISPLAY_NAME}</display_name> <device_name>${DISPLAY_NAME}</device_name> <name>${DISPLAY_NAME}</name> <asset_tag>${ASSET_TAG}</asset_tag> <serial_number>${SERIAL_NUMBER}</serial_number> </general> <location> <department>${DEPARTMENT}</department> <building>${BUILDING}</building> <username>${USER_NAME}</username> <real_name>${USER_NAME}</real_name> <email_address>${EMAIL_ADDRESS}</email_address> </location>
</mobile_device>
EOF

curl -X PUT -H "Accept: application/xml" -H "Content-type: application/xml" -k -u jssAPIUsername:jssAPIPassword! -T "/Users/$Home/Desktop/CasperImports/$DISPLAY_NAME.xml" "https://yourjss.com:8443/JSSResource/mobiledevices/mobiledevices/serialnumber/$SERIAL_NUMBER"

done

**