Renaming computers using asset_tag data (API)

Sean_M_Harper
Contributor

I just inherited a JSS one week after a 650 Macbook Air deploy. In this deploy, no machines have been bound or named, but asset tag info was recorded into the JSS (in the asset_tag field). Each of them has the name "Macbook Air" or "User's Macbook Air".

What I need to do:

  1. Rename the devices (both in actuality and in the JSS) using data already stored in the asset_tag field of the JSS record for each machine.

  2. The names need to be changed to the asset tag with “-MAC” after it. An example is: If my asset tag is 12345, my computer name needs to be “12345-MAC”.

I need to be able to run this script in a policy, once against each machine to change its name. Only after this is done can I move forward and begin to bind machines to active directory.

Any assistance would be great, and thanks in advance!

1 ACCEPTED SOLUTION

derivethegeek
New Contributor II

Hello,

After working with Sean_M_Harper for about 30 minutes or so, we were able to come up with this working solution.

#!/bin/bash

MACADDRESS=$(networksetup -getmacaddress en0 | awk '{ print $3 }')
JSS=https://jss.example.com:8443
API_USER=username
API_PASS=password
ASSET_TAG_INFO=$(curl -k $JSS/JSSResource/computers/macaddress/$MACADDRESS --user $API_USER:$API_PASS | cut -d "," -f 12 | cut -d ":" -f 2 | sed 's/"//g')
SERIAL_NUMBER=$(system_profiler SPHardwareDataType | awk '/Serial/ {print $4}')
SUFFIX="-MAC"

if [ -n "$ASSET_TAG_INFO" ]; then
  echo "Processing new name for this client..."
  echo "Changing name..."
  scutil --set HostName "$ASSET_TAG_INFO"$SUFFIX
  scutil --set ComputerName "$ASSET_TAG_INFO"$SUFFIX
  echo "Name change complete. ("$ASSET_TAG_INFO"$SUFFIX)"

else
  echo "Asset Tag information was unavailable. Using Serial Number instead."
  echo "Changing Name..."
  scutil --set HostName $SERIAL_NUMBER$SUFFIX
  echo "Name Change Complete ($SERIAL_NUMBER$SUFFIX)"

fi

Basically, the first 'if' statement will check if the string $ASSET_TAG_INFO is null; if so, proceed to rename with serial number (as to not end up with blank or weird names) and your preferred suffix. If not, continue on and rename with info pulled from the JSS and preferred suffix. Quite simple, actually.

With the flexibility of cut, you can determine any field you would like to pull and perform similar actions for other requests. Either way, hopefully someone will find this helpful in the future.

Regards.

View solution in original post

18 REPLIES 18

derivethegeek
New Contributor II

Hello,

After working with Sean_M_Harper for about 30 minutes or so, we were able to come up with this working solution.

#!/bin/bash

MACADDRESS=$(networksetup -getmacaddress en0 | awk '{ print $3 }')
JSS=https://jss.example.com:8443
API_USER=username
API_PASS=password
ASSET_TAG_INFO=$(curl -k $JSS/JSSResource/computers/macaddress/$MACADDRESS --user $API_USER:$API_PASS | cut -d "," -f 12 | cut -d ":" -f 2 | sed 's/"//g')
SERIAL_NUMBER=$(system_profiler SPHardwareDataType | awk '/Serial/ {print $4}')
SUFFIX="-MAC"

if [ -n "$ASSET_TAG_INFO" ]; then
  echo "Processing new name for this client..."
  echo "Changing name..."
  scutil --set HostName "$ASSET_TAG_INFO"$SUFFIX
  scutil --set ComputerName "$ASSET_TAG_INFO"$SUFFIX
  echo "Name change complete. ("$ASSET_TAG_INFO"$SUFFIX)"

else
  echo "Asset Tag information was unavailable. Using Serial Number instead."
  echo "Changing Name..."
  scutil --set HostName $SERIAL_NUMBER$SUFFIX
  echo "Name Change Complete ($SERIAL_NUMBER$SUFFIX)"

fi

Basically, the first 'if' statement will check if the string $ASSET_TAG_INFO is null; if so, proceed to rename with serial number (as to not end up with blank or weird names) and your preferred suffix. If not, continue on and rename with info pulled from the JSS and preferred suffix. Quite simple, actually.

With the flexibility of cut, you can determine any field you would like to pull and perform similar actions for other requests. Either way, hopefully someone will find this helpful in the future.

Regards.

Sean_M_Harper
Contributor

Thanks derivethegeek, I appreciate the help! Lets hope this script will help others begin to use the API :)

alexjdale
Valued Contributor III

Another option besides cut is xpath, something like:

ASSET_TAG_INFO=$(curl -k $JSS/JSSResource/computers/macaddress/$MACADDRESS --user $API_USER:$API_PASS |  xpath /computer/general/asset_tag | awk '{gsub(/<[^>]*>/,"")};1')

I use xpath because it lets me drill right to the node I need by name, it sounds like cut might be relying on data being on a specific line in the API result every time?

Sean_M_Harper
Contributor

Personally I have never used xpath, but its likely a far more "fool proof" method. I will look into this as a way to enhance this script.

MrP
Contributor III

I did this before I saw ajaxdale's post. Same concept of grabbing the correct value no matter what the position in the results.

ASSET_TAG_INFO=$(curl -k $JSS/JSSResource/computers/macaddress/$MACADDRESS --user $API_USER:$API_PASS  | awk 'BEGIN { FS = "asset_tag" } ; {print $2}'  | awk -F, '{print $1}' | awk 'BEGIN { FS = """ } ; { print $3}')

BrysonTyrrell
Contributor II

If you're extracting a value using xpath you don't need to pipe out to awk of another utility:

ASSET_TAG_INFO=$(curl -k $JSS/JSSResource/computers/macaddress/$MACADDRESS --user $API_USER:$API_PASS |  xpath '/computer/general/asset_tag/text()')

MrP
Contributor III

@brysontyrrell Excellent! Jamf changed the formatting between 9.93 and 9.96 from "," to "<>". I assume it's xml. Anyway what I wrote immediately stopped working after upgrading. Using your line grabs the value perfectly.

wlevan
New Contributor III

Don't mean to hijack this thread but.....Is there an update for the script to do it with Jamf Cloud? I tried and it won't connect.

mwineke
New Contributor

So, for our purposes, we're using the UUID (local) as UDID (Jamf Pro field) for record matching purposes.
This following works, and eliminates xpath (which was erroring out):

assettag=$(curl -k -u "${user}:${pass}" ${jssurl}/JSSResource/computers/udid/${udid} -X GET | awk 'BEGIN { FS = "asset_tag" } ; {print $2}' | cut -f2 -d ">" | cut -f1 -d "<")

Thanks everyone, for all of the data parsing wizardry!

Mauricio
Contributor III

Big Sur has changed the xpath

For an explanation:
https://scriptingosx.com/2020/10/dealing-with-xpath-changes-in-big-sur/

To make this call work

ASSET_TAG_INFO=$(curl -k $JSS/JSSResource/computers/macaddress/$MACADDRESS --user $API_USER:$API_PASS |  xpath '/computer/general/asset_tag/text()')

Change it to

ASSET_TAG_INFO=$(curl -k $JSS/JSSResource/computers/macaddress/$MACADDRESS --user $API_USER:$API_PASS |  xmllint --xpath '/computer/general/asset_tag/text()' -)

So, updated for Big Sur it should be like this:

 

#!/bin/bash

MACADDRESS=$(networksetup -getmacaddress en0 | awk '{ print $3 }')
JSS=https://xxxxxx.jamfcloud.com:8443
API_USER=username
API_PASS=password
ASSET_TAG_INFO=$(curl -k $JSS/JSSResource/computers/macaddress/$MACADDRESS --user $API_USER:$API_PASS | xmllint --xpath '/computer/general/asset_tag/text()' -)
SERIAL_NUMBER=$(system_profiler SPHardwareDataType | awk '/Serial/ {print $4}')
PREFIX="Company"
SUFFIX="MAC"

if [ -n "$ASSET_TAG_INFO" ]; then
echo "Processing new name for this client..."
echo "Changing name..."
scutil --set HostName $PREFIX"$ASSET_TAG_INFO"$SUFFIX
scutil --set ComputerName $PREFIX"$ASSET_TAG_INFO$"SUFFIX
echo "Name change complete. ($PREFIX"$ASSET_TAG_INFO"$SUFFIX)"

else
echo "Asset Tag information was unavailable. Using Serial Number instead."
echo "Changing Name..."
scutil --set HostName $PREFIX$SERIAL_NUMBER$SUFFIX
echo "Name Change Complete ($PREFIX$SERIAL_NUMBER$SUFFIX)"

fi

 I still get an issue with the assetTag not populating, and still reverting to serial number.

Edit: Proofreading is not my strong side. Reverting to port 443(For Jamf Pro cloud deployment) instead of 8443(Jamf Pro On-prem) solved it. Naming based on asset tag info is now working in Mac OS Monterey :)

Mauricio
Contributor III

set the bash script to verbose so you can see where the issue is

#!/bin/bash
set -x
....

 Is happening in all runs? Some devices? 

It could be MACADDRESS mismatch, non existent in Jamf.

ASSET_TAG_INFO could not return anything, if there are duplicates you will get a 409 (Conflict), maybe API account... 

I would add extra checks for any API call just in case it fails (and it does)

It happens in the test environment at the customer(scoped to 2 computers) og my own setup. Total of 3 computers running Monterey.

The ASSET_TAG_INFO is definitely not populating, as it reverts to the ELSE command. If that is due to the MACADRESS or the actual  ASSET_TAG_INFO I have not yet figured out. The Api works, at it is able to set the alternative name with serial in the ELSE command.

Mauricio
Contributor III

You can get the ASSET_TAG_INFO in the else part because of the SERIAL_NUMBER variable is local.

Have you added the 

set -x 

in the script and got all info rom those test Macs?

Post the findings here so we can have a look

It seems that my testing with ports 443 and 8443 was not complete. It seems to me port 443 is for external/Jamf Cloud, 8443 for Jamf On-prem instances.

Following your -x approach, and letting BBEdit output to file(Unix script output halted, never completed), the script worked! Thanks @Mauricio

Mauricio
Contributor III

It is amazing how external factors put a spanner in the works.

Glad that you got it sorted

In this case the customer in question had an on-prem setup, and my test instance of Jamf is in the cloud. Different environments, different settings to apply.

Edit: Nevermind, it's working now. Had to get the JSS admin password from above my paygrade to put in for the API user variables. Thanks to everyone that helped make this easier.

Maybe you or anyone else may be able to help me figure out what I have going on with this script. The error is occurring when trying to pull the asset tag info.

 

 

Script result:   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100   422  100   422    0     0    695      0 --:--:-- --:--:-- --:--:--   700
100   422  100   422    0     0    694      0 --:--:-- --:--:-- --:--:--   699
-:10: parser error : Opening and ending tag mismatch: br line 8 and p
</p>
    ^
-:11: parser error : Opening and ending tag mismatch: p line 8 and body
</body>
       ^
-:12: parser error : Opening and ending tag mismatch: body line 5 and html
</html>
       ^
-:12: parser error : Premature end of data in tag html line 1
</html>
       ^
Asset Tag information was unavailable. Using Serial Number instead.

 

I don't do a lot of coding, but I know enough to look for those opening tags it thinks should be there and I don't have any idea. I found a different proposed solution here to add -H and GET to the curl line. if I change mine to 

 

ASSET_TAG_INFO=$(curl -k -H "$JSS/JSSResource/computers/macaddress/$MACADDRESS --user $API_USER:$API_PASS" GET | xmllint --xpath '/computer/general/asset_tag/text()' -)

 

I get the following error: 

 

Could not resolve host: GET
-:1: parser error : Document is empty

^

 

That feels like a step in the right direction due to less issues but may be completely off track. I reverted back to how it is originally written and added in the 'set -x' line but it doesn't seem to be giving me any more information. I still get "Asset Tag information was unavailable" and it shows "ASSET_TAG_INFO= "; I set the Asset Tag manually in this particular computer's record and it's still there even after the script changes the name correctly albeit with serial number. 

 

I am personally okay with using the serial number for the name but I have had serious fights with teachers over computer names; it was too much trouble to remember the two digit number I assigned to the computers to give students for AirDrop so I can only imagine the fit that will be thrown if they have to use the serial number.