Skip to main content

Hello,



I am in need of a script to rename hundreds of ios devices. I would like to do it using a CSV file. One column with the serial number and the next column with the name of the ios device. I know about the mut software, however we are unable to use it as we have different IT departments and the mut software tests privileges that we do not want to give the users.



Any help with this dilemma would be greatly appreciated as I am sure someone has the script handy.

please


You should be able to modify this to fit your needs.



#!/bin/sh

# Name: leaseupdate.sh
# Date: 9 March 2015
# Author: Steve Wood (swood@integer.com)
# Purpose: used to read in lease data from a CSV file and update the record in the JSS
# The CSV file needs to be saved as a UNIX file with LF, not CR
# Version: 1.0
#
# A good portion of this script is re-purposed from the script posted in the following JAMF Nation article:
#
# https://jamfnation.jamfsoftware.com/discussion.html?id=13118#respond
#

jssAPIUsername="<apiuser>"
jssAPIPassword="<apipassword>"
jssAddress="https://your.jss.com:8443"
file="<path-to-csv-file>"

#Verify we can read the file
data=`cat $file`
if [[ "$data" == "" ]]; then
echo "Unable to read the file path specified"
echo "Ensure there are no spaces and that the path is correct"
exit 1
fi

#Find how many computers to import
computerqty=`awk -F, 'END {printf "%s
", NR}' $file`
echo "Computerqty= " $computerqty
#Set a counter for the loop
counter="0"

duplicates=[]

id=$((id+1))

#Loop through the CSV and submit data to the API
while [ $counter -lt $computerqty ]
do
counter=$[$counter+1]
line=`echo "$data" | head -n $counter | tail -n 1`
serialNumber=`echo "$line" | awk -F , '{print $1}'`
leaseExpires=`echo "$line" | awk -F , '{print $2}'`

echo "Attempting to update lease data for $serialNumber"

# use serialNumber to locate the ID of the comptuer
### Add some logic to test for an empty set coming back from serial number check.
myOutput=`curl -su ${jssAPIUsername}:${jssAPIPassword} -X GET ${jssAddress}/JSSResource/computers/serialnumber/$serialNumber`
myResult=`echo $myOutput | xpath /computer/general/id[1] | awk -F'>|<' '/id/{print $3}'`
myID=`echo $myResult | tail -1`

echo $serialNumber " " $myID " " $leaseExpires
apiData="<computer><purchasing><lease_expires>$leaseExpires</lease_expires></purchasing></computer>"
output=`curl -sS -k -i -u ${jssAPIUsername}:${jssAPIPassword} -X PUT -H "Content-Type: text/xml" -d "<?xml version="1.0" encoding="ISO-8859-1"?>$apiData" ${jssAddress}/JSSResource/computers/id/$myID`

echo $output
#Error Checking
error=""
error=`echo $output | grep "Conflict"`
if [[ $error != "" ]]; then
duplicates+=($serialnumber)
fi
#Increment the ID variable for the next user
id=$((id+1))
done

echo "The following computers could not be created:"
printf -- '%s
' "${duplicates[@]}"

exit 0

The MUT also does this and makes it simple with a nice UI.


Yeah we would love to use the MUT but are not able to because of how our jss is set up. We are a tunnel on another JSS account for a sister IT department... Its really confusing and frustrating as MUT would be the answer to our dilemma.



Is there anyway you can advise me on how to setup your code to rename the ios devices? How do I change lease to device name? I understand CSV loop however this is confusing. If our devices are already in DEP do I need to locate them by serial number?


Remember you could also use variables to set the name of a device. Anytime the device checks-in, the name will change back.



http://krypted.com/mac-security/using-payload-variables-in-profile-manager/


Yes! However I am getting a little bit of a crash course on some of this coding... (I am a junior in college and know enough to be dangerous lol) any help anyone can contribute would be of great appreciation... I am learning a lot through forums like these that is for sure.


@jay216 Ey! I'm a young'n also (21). Basically change the variable name in line where it it says leaseExpires=echo "$line" | awk -F , '{print $2}'
so change it to name or something like that. If you do your csv's in excel like i do then column 1 is your device serial number and column 2 is the name for it. The other thing you have to do is modify the xml portion. Where it says apiData="<computer><purchasing><lease_expires>$leaseExpires</lease_expires></purchasing></computer>" you need to change it to the xml format for the ios devices. I don't know it because we only do mac's here. Basically go to yourjss.com:8443/api and the should be an IOS get command somewhere. use it to get the XML structure you need for you "put" in the API. You don't need all the data. Just the data that's being changed. So the hierarchy is computer>purchasing>lease expires and then closing brackets for that respectively. Yours would be something like mobiledevices>name or something along those lines. Make sure when you change any variables in one place of the script you change them in any others. Find and replace all will be your friend for that but be careful to not changing something you don't want to.


ahhhh you have shown me the light... I am busting notepad out now and will keep you updated.


Okay I have everything except the API data. I am unsure of where to find it. I do not see anything that says IOS in the API let alone rename.



It would have to be under mobile devices I am sure




anything look like api data?


That's the right information. I think you would put your ${name} Variable inside of <device_name> so it would be <mobile_device><device_name>${namevariable}</device_name></mobile_device>



You also need to change the myoutput variable and the output variable tot he correct api call. so your myoutput ending should be something like GET /mobiledevices/serialnumber/$serialnumber



and your output ending would be something like /mobiledevices/id/${myid}


Anyone interested in taking a call on this and discussing how this worked for you. Let me know


When I set mine up I couldn't get the xml method to work, It would update JAMF Pro but the name would not stick

We wound up using the rename command in the code below and this has worked well for us.
Please ignore the bad formatting and underlining.

Regards
Graeme

Preamble



import urllib.parse
import urllib.request
import urllib.response
import urllib
import pypyodbc
import sys
import csv
import codecs
import xml.etree.cElementTree as etree
import getpass
from urllib.request import urlopen
import time
import datetime
from time import strftime
from datetime import datetime
from datetime import date
from operator import itemgetter, attrgetter
import mysql.connector

global set to not verify ssl certificate. Bad practice but works here.



import ssl
ssl._create_default_https_context = ssl._create_unverified_context

userName=input('Username: ')
passWord=getpass.getpass('Password: ')
top_level_url = "https://mdm.ourschool.edu.au:8443/JSSResource"

#create an authorization handler and add to all requests
p = urllib.request.HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, top_level_url, userName, passWord);
auth_handler = urllib.request.HTTPBasicAuthHandler(p)
opener = urllib.request.build_opener(auth_handler)
opener.addheaders.append(('Accept', 'application/xml'))
urllib.request.install_opener(opener)

This will post an XML but is not used here.



def sendXMLtoJSS(resource, method = '', data = None):
request = urllib.request.Request(resource)
#if method.upper() in ('POST', 'PUT', 'DELETE'):
#request.get_method = lambda: method

if method.upper() in ('POST', 'PUT') and data:

headers = { 'Content-Type' : 'text/xml' }

#data = urllib.parse.urlencode(data)
data = data.encode('ascii')
req = urllib.request.Request(resource, data, headers)
req.get_method = lambda: method
#req.get_method = method
with urllib.request.urlopen(req) as response:
the_page = response.read()
return the_page
#opener.addheaders.append('Content-Type', 'text/xml')
#request.add_header('Content-Type', 'text/xml')
#return opener.open(request, data)
else:
try:
return opener.open(resource)
except IOError as e:
print (e)
logData(e)

This is the rename command.



def sendRenameCommandtoJSS(id, New_Name):

# JAMF says if we are enforcing the name send a command because it is friendlier for cloud customers
# but uploading an xml updated the jss but did not save the settings. Had to manually go to the device
# properties in JSS and click the edit and then save.
# Will error out with a 500 error if a rename command is still outstanding.
Devicename = urllib.parse.quote(New_Name)
command = top_level_url "/mobiledevicecommands/command/DeviceName/" Devicename "/id/" str(id)
req = urllib.request.Request(command)

req.get_method = lambda: 'POST'
#request = urllib.request.Request(resource)
try:
response = opener.open(req)
strResponse = response.read().decode('utf-8')
logData(strResponse)
print(New_Name " has been successfully renamed.")
#logData(response.read().decode('utf-8'))
except urllib.error.HTTPError as e:
if e.code == 400:
print(New_Name
" has an outstanding rename request. Rename failed.")
else:
print("Rename Error" str(e), command)

This gets the list of devices from the JSS so we can extract the ID



def getDevices():
#Download from JSS an xml list of devices and basic attributes.
response = sendXMLtoJSS(top_level_url
'/mobiledevices')
responseBytes = response.read()
responsetext = responseBytes.decode("utf-8", 'ignore')
responsetext = unicodeToAscii(responsetext)#Remove special characters.
#print(responsetext)
xml = etree.fromstring(responsetext)
#text_file = open("Output.xml", "wb")
#text_file.write(responsetext)
#text_file.close()
return xml

def getDeviceList(xmlOfDevices):
for child in xmlOfDevices:
#print(child.tag, child.text)
deviceId = ""
deviceSerial = ""
deviceUsername = ""
deviceName = ""
deviceSupervised = ""
try:
temp = len(devices)
except:
devices = []

for group in child:
#print(group.tag, group.text)
if group.tag == "id":
deviceId = group.text
if group.tag == "serial_number":
deviceSerial = group.text
if group.tag == "username":
deviceUsername = group.text
if group.tag == "device_name":
deviceName = group.text
if group.tag == "supervised":
deviceSupervised = group.text
#if deviceId == "63":
# print ("ID = 63")
device = [deviceId, deviceSerial, deviceUsername, deviceName, deviceSupervised]
devices.append(device)
return devices

I have a FileMaker database that does this (and more).



It uses the API to first GET all your mobile devices from your JSS and puts them into FileMaker. Then you can use FileMaker to name them however you want. You can then PUT (update) them back into the JSS. Works great.



You can also PUT the Department, Room, Username, Real_Name, email, Building all at the same time as well.



Send me an email (if you use FileMaker) and I will share my database with you.


Reply