Name computer using JSS username

mottertektura
Contributor

Greetings! I have this script that uses the API to pull the username that's assigned to the computer in the JSS and then name the computer with it.

#!/bin/sh

jssUser=$4
jssPass=$5
jssHost=$6

serial=$(system_profiler SPHardwareDataType | awk '/Serial/ {print $4}')

response=$(curl -k -s ${jssHost}/JSSResource/computers/serialnumber/${serial}/subset/location --user ${jssUser}:${jssPass})
real_name=$(echo $response | /usr/bin/awk -F'<username>|</username>' '{print $2}' | cut -c1-11);

if [ "$real_name" == "" ]; then
    echo "Error: Username field is blank."
    exit 1

else

/usr/sbin/scutil --set HostName "$real_name"
/usr/sbin/scutil --set LocalHostName "$real_name"
/usr/sbin/scutil --set ComputerName "$real_name"

fi

I think the problem is with:

real_name=$(echo $response | /usr/bin/awk -F'<username>|</username>' '{print $2}' | cut -c1-11);

...but I'm not sure what needs to be fixed in order to get it to print the just username again.

Thanks!

2 ACCEPTED SOLUTIONS

mm2270
Legendary Contributor III

@mottertektura Are you certain the username and password you're passing to the script have the necessary privileges to get the info? The error you posted would indicate the curl command didn't pass anything to the xmllint command (which formats the xml output)

Another possibility, which I forgot about before - the JSS may be sending back JSON data, not xml.

Try this adjustment to see if you get better results.

real_name=$(/usr/bin/curl -H "Accept: text/xml" -sfku "${jssUser}:${jssPass}" "${jssHost}/JSSResource/computers/serialnumber/${serial}/subset/location" | xmllint --format - 2>/dev/null | awk -F'>|<' '/<username>/{print $3}')

The above should force XML, not JSON, and also will pipe any errors from the command to /dev/null so it should return a blank result if there are any problems, like the username/password being incorrect for example.

View solution in original post

mottertektura
Contributor

Here's the working script:

#!/bin/sh

jssUser=$4
jssPass=$5
jssHost=$6

serial=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}')

username=$(/usr/bin/curl -H "Accept: text/xml" -sfku "${jssUser}:${jssPass}" "${jssHost}/JSSResource/computers/serialnumber/${serial}/subset/location" | xmllint --format - 2>/dev/null | awk -F'>|<' '/<username>/{print $3}')

if [ "$username" == "" ]; then
    echo "Error: Username field is blank."
    exit 1

else

/usr/sbin/scutil --set HostName "$username"
/usr/sbin/scutil --set LocalHostName "$username"
/usr/sbin/scutil --set ComputerName "$username"

fi

View solution in original post

20 REPLIES 20

mm2270
Legendary Contributor III

I'd change it to look like this:

real_name=$(/usr/bin/curl -sfku "${jssUser}:${jssPass}" "${jssHost}/JSSResource/computers/serialnumber/${serial}/subset/location" | xmllint --format - | awk -F'>|<' '/<username>/{print $3}')

And get rid of the reponse line, since there should be no need to first store the response and then echo it back to get the string you're looking for. It can be done in one attempt, with the curl command.

Try that and see how it works.

Also just want to point out that sometimes system_profiler is a little slow. A slightly faster way to get the Mac's Serial Number is:

ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}'

mottertektura
Contributor

Thanks for your help, mm2270!

I took out the response line and made the change but now I'm getting this error message:

-:1: parser error : Start tag expected, '<' not found

mm2270
Legendary Contributor III

@mottertektura Are you certain the username and password you're passing to the script have the necessary privileges to get the info? The error you posted would indicate the curl command didn't pass anything to the xmllint command (which formats the xml output)

Another possibility, which I forgot about before - the JSS may be sending back JSON data, not xml.

Try this adjustment to see if you get better results.

real_name=$(/usr/bin/curl -H "Accept: text/xml" -sfku "${jssUser}:${jssPass}" "${jssHost}/JSSResource/computers/serialnumber/${serial}/subset/location" | xmllint --format - 2>/dev/null | awk -F'>|<' '/<username>/{print $3}')

The above should force XML, not JSON, and also will pipe any errors from the command to /dev/null so it should return a blank result if there are any problems, like the username/password being incorrect for example.

mottertektura
Contributor

@mm2270 That did the trick! Thanks so much for your help, I really appreciate it!

mottertektura
Contributor

Here's the working script:

#!/bin/sh

jssUser=$4
jssPass=$5
jssHost=$6

serial=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}')

username=$(/usr/bin/curl -H "Accept: text/xml" -sfku "${jssUser}:${jssPass}" "${jssHost}/JSSResource/computers/serialnumber/${serial}/subset/location" | xmllint --format - 2>/dev/null | awk -F'>|<' '/<username>/{print $3}')

if [ "$username" == "" ]; then
    echo "Error: Username field is blank."
    exit 1

else

/usr/sbin/scutil --set HostName "$username"
/usr/sbin/scutil --set LocalHostName "$username"
/usr/sbin/scutil --set ComputerName "$username"

fi

Hi 

This would be the perfect script i am looking for. Anyway i receive the "username field is blank" 
What kind of permissions should the api user have?

Andy_McCaskill
Contributor

This script works wonderfully. Any chance you can have it query the "Full Name" section instead?

mottertektura
Contributor

@mccaskill Sorry for the late response! I believe you would just need to slightly alter it and change the /<username> to /<real_name> something like this:

#!/bin/sh

jssUser=$4
jssPass=$5
jssHost=$6

serial=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}')

username=$(/usr/bin/curl -H "Accept: text/xml" -sfku "${jssUser}:${jssPass}" "${jssHost}/JSSResource/computers/serialnumber/${serial}/subset/location" | xmllint --format - 2>/dev/null | awk -F'>|<' '/<real_name>/{print $3}')

if [ "$username" == "" ]; then
    echo "Error: Username field is blank."
    exit 1

else

/usr/sbin/scutil --set HostName "$username"
/usr/sbin/scutil --set LocalHostName "$username"
/usr/sbin/scutil --set ComputerName "$username"

fi

mstensond49
New Contributor II

So what entries need edited in this script for it to work?

mm2270
Legendary Contributor III

@mstensond49 I don't see anything in the above that would need to be changed for the script to work. I can't be 100% sure since I haven't run that exact version on anything, but it looks ok to me. Basically you would need to supply the API credentials (username & password) to the script in parameters 4 and 5 respectively. And your JSS URL in parameter 6.

Is the script not working for you when you try it?

mstensond49
New Contributor II

It is not working for me no, I am going to do some more testing. Thanks!

mstensond49
New Contributor II

It is not working for me no, I keep getting "username field is blank" and I have verified that there is in fact a username accosiated with the JSS record. Any thoughts? I am going to do some more testing. Thanks!

mm2270
Legendary Contributor III

@mstensond49 Ok, so let's break things down a bit.

In the script above, if it returns "username field is blank" it means the API curl command either did not pull down a value, or the username field in the computer record is blank. Since we know it's not the former as you verified the username field is populated, then it may be that the API credentials you're supplying to the script aren't correct, or don't have the correct permissions. It could also be the JSS URL you're supplying in parameter 6 has a trailing slash in it. IOW, if your JSS URL is https://myjss.acme.org:8443/, you want to make sure what you enter does not have a final / at the end. As you can see in the curl command, it's using "${jssHost}/JSSResource/computers/serialnumber/${serial}/subset/location" There is already a slash between ${jssHost} and /JSSResource/ so if the value you supply for jssHost or parameter 6 has a slash already, the path becomes invalid. I've made a habit in my API scripts of massaging the value supplied in the parameter to ensure it does not have that slash in it by passing it through a sed command to remove any final slash the user may have provided by accident. This script does not have that, but I would check on that to be sure it's formatted the way the script expects it to be.

The other thing is, are you using the previous script version that is getting username or the more recent one just before your first post on this thread? I ask because the latter one is looking for real_name not username The Real name is the full name, which may or may not be populated in your JSS, depending on how you have things set up.

mstensond49
New Contributor II

I am using the script that is calling the username. There is no slash. I tried with my actual username and credentials and it worked beautifully. The system prompted me for a password so assume I need to use sudo before the command. I will look at my permissions for the admin account I would like to use as I would rather not put my creds in the script. Thank again for your help!

mm2270
Legendary Contributor III

Well, the script is intended to run from a Jamf Pro policy, in which case it would be running with admin/root privileges. So no, there does not need to be a sudo in the script. In fact, if you wanted to test it outside of a policy, you would just run the entire script with sudo:
sudo /path/to/script.sh
This is preferable to adding sudo into the script itself.

As for why it's coming back blank, I think you will need to check on the API credentials you're supplying to the script. It's possible it doesn't have the correct read permissions. It would only need to be able to read Computer objects in your JSS. It shouldn't actually need anything else.

mstensond49
New Contributor II

Figured it out. The password we were using for the admin account had $$ and we just needed to add single quotes so the script isnt recogizing them as variables. It's working beautifully now. Thanks for your assistance. I really appriciate it.

eagleone
New Contributor

Would one of you provide an example of how this actually looks when you enter your variables? I'm currently doing this:

#!/bin/sh

jssUser=myadminuser
jssPass=mypassword
jssHost=https://my.jss.com:8443

serial=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}')

username=$(/usr/bin/curl -H "Accept: text/xml" -sfku "${jssUser}:${jssPass}" "${jssHost}/JSSResource/computers/serialnumber/${serial}/subset/location" | xmllint --format - 2>/dev/null | awk -F'>|<' '/<username>/{print $3}')

if [ "$username" == "" ]; then
    echo "Error: Username field is blank."
    exit 1

else

/usr/sbin/scutil --set HostName "$username"
/usr/sbin/scutil --set LocalHostName "$username"
/usr/sbin/scutil --set ComputerName "$username"

fi

Is this correct?

mstensond49
New Contributor II

Awesome! You will leave it like this. Then set the variables in Casper Admin and the JSS when you build the policy. I have added the model as well so the result for the computer name looks something like this. " jsmith MacBook Air (13-inch Early 2015)" I would not recommendf this if you are binding these Macs to AD as it is a very long name. Super easy on the eyes when listed in the JSS though.

Major credit to @mottertektura for all of this.

#!/bin/sh

jssUser=$4
jssPass=$5
jssHost=$6

serial=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}')

username=$(/usr/bin/curl -H "Accept: text/xml" -sfku "${jssUser}:${jssPass}" "${jssHost}/JSSResource/computers/serialnumber/${serial}/subset/location" | xmllint --format - 2>/dev/null | awk -F'>|<' '/<username>/{print $3}')

modelName=$(/usr/bin/curl -H "Accept: text/xml" -sfku "${jssUser}:${jssPass}" "${jssHost}/JSSResource/computers/serialnumber/${serial}/subset/hardware" | xpath /computer/hardware/model[1] | awk -F'>|<' '/<model>/{print $3}')

## If either the username or model name came back blank from the above API calls, exit
if [[ "$username" == "" ]] || [[ "$modelName" == "" ]]; then
    echo "Error: The Username or Model Name field is blank."
    exit 1
else
    fullCompName="${username} ${modelName}"

    /usr/sbin/scutil --set HostName "$fullCompName"
    /usr/sbin/scutil --set LocalHostName "$fullCompName"
    /usr/sbin/scutil --set ComputerName "$fullCompName"
fi

eagleone
New Contributor

Edit: The script by itself did work. However, I'm using it as part of a policy that includes a network bind which is not working. Basically, I'm trying to rename a DEP computer before it binds to the network. If I can do this, I'll take the afternoon off :)

OK...mine is not working. I set my variables right under the #!/bin/sh as:

#!/bin/sh
jssUser=myjssadmin
jssPass=myjsspassword
jssHost=https://mdm.myjss.com:8443

I'm not sure if there's something in the password that may be stopping it from working or what. My first character of the PW is a number. Would that have an adverse effect?

mottertektura
Contributor

Glad to hear that this is working for you @mstensond49 ! I'm doing something similar, but since we are binding to AD :( ... I'm using cut to truncate the username so we don't exceed the 15 character limit in AD and then appending it with an abbreviation for the model like this:

#!/bin/sh

jssUser=$4
jssPass=$5
jssHost=$6

serial=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}')

username=$(/usr/bin/curl -H "Accept: text/xml" -sfku "${jssUser}:${jssPass}" "${jssHost}/JSSResource/computers/serialnumber/${serial}/subset/location" | xmllint --format - 2>/dev/null | awk -F'>|<' '/<username>/{print $3}' | cut -c1-11)

model=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/model/{print $4}' model=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/model/{print $4}') | sed 's/[0-9]*//g')

if [ "$username" == "" ]; then
    echo "Error: Username field is blank."
    exit 1

fi

if [ "$model" == "MacBook," ]; then

/usr/sbin/scutil --set HostName "$username-mb"
/usr/sbin/scutil --set LocalHostName "$username-mb"
/usr/sbin/scutil --set ComputerName "$username-mb"

fi

if [ "$model" == "MacBookAir," ]; then

/usr/sbin/scutil --set HostName "$username-mba"
/usr/sbin/scutil --set LocalHostName "$username-mba"
/usr/sbin/scutil --set ComputerName "$username-mba"

fi

if [ "$model" == "MacBookPro," ]; then

/usr/sbin/scutil --set HostName "$username-mbp"
/usr/sbin/scutil --set LocalHostName "$username-mbp"
/usr/sbin/scutil --set ComputerName "$username-mbp"

fi

if [ "$model" == "iMac," ]; then

/usr/sbin/scutil --set HostName "$username-mac"
/usr/sbin/scutil --set LocalHostName "$username-mac"
/usr/sbin/scutil --set ComputerName "$username-mac"

fi

if [ "$model" == "MacPro," ]; then

/usr/sbin/scutil --set HostName "$username-mp"
/usr/sbin/scutil --set LocalHostName "$username-mp"
/usr/sbin/scutil --set ComputerName "$username-mp"

fi

echo "New computer name is now: $username-xxx"

exit 0

@eagleone , Do you have a Directory payload set up in your PreStage enrollment to bind to AD? If so, I would recommend using a variable in the Client ID field to name the computer record and then using the script to rename the computer after it is enrolled in the JSS. That's how I have things set up and I haven't had any problems with the AD computer record and computer name being different.

7722c9b2477a46218070e298b0abee80