Mass rename of IOS devices script

jay216
New Contributor II

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.

16 REPLIES 16

jay216
New Contributor II

please

Asnyder
Contributor III

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

chris_miller
Contributor

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

jay216
New Contributor II

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?

jared_f
Valued Contributor

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/

jay216
New Contributor II

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.

Asnyder
Contributor III

@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.

jay216
New Contributor II

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

jay216
New Contributor II

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

jay216
New Contributor II

e70f5729918f4398825c6000962631a6

jay216
New Contributor II

1f41b79b18f5458f8451afa868a8ec61

jay216
New Contributor II

anything look like api data?

Asnyder
Contributor III

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}

labanh
New Contributor

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

Graeme
Contributor
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

bvondeylen
Contributor II

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.