DEPnotify Starter Script to assign computer name based on the user logging in...

GabeShack
Valued Contributor III

Long subject i know lol.

I am trying to make a script that will take the user logging into the computer for the first time and name the computer appropriately based on that users info.

I.E.  If the user is a high school student, it would assign HS-StudentAssetTag#, if a Middle School teacher, MS-TeacherAssetTag#, or if a Principal or other Administrator of one of the grade schools GS-AdminAssetTag#

I think I have the commands already to pull the building name (which @mm2270 helped me figure a way to assign that based on the students "Grade" populated in our "Position" field) but I'm needing it to be a bit more robust since that would only work for middle and high, if its a Grade school it could be 1 of 4 different buildings.  

All the info is in our AD and pulled from PowerSchool (and we also use One Sync/Class Link Roster Server), I just need to find a good way to pull that info with a script that grabs the building(which could be based on security groups or OU), the title(position for staff or for students = grade number), and then finishes with grabbing the computers Asset Tag which would get added onto the end.  If I can automate this during the login, then I can assign automated policies for the different computer names and just have one enrollment workflow instead of making one for each type of user or group.

 

Thanks to anyone with any good thoughts on this!

Keywords:

Scripts, Active Directory, K-12, Azure, Organizational Units, Shell, Python, Bash, Jamf Infrastructure Manager, JIM.

(I still don't get how the new JamfNation Keywords or "labels" work).

Gabe Shackney
Princeton Public Schools
3 ACCEPTED SOLUTIONS

mm2270
Legendary Contributor II

Sorry @GabeShack It just occurred to me you asked about avoiding a false positive based on possible student or faculty usernames. You could try doing something like this to reformat the string to only include the "OU" items and exclude the "CN" and "DC" sections

 

OU_VALUES=$(/bin/echo "$LDAP_EA_VALUE" | tr ',' '\n' | grep "^OU=" | tr '\n' ' ')

 

The above would produce the following string to use in the case statement or your original if/then/else grep script.

 

OU=11 OU=PHS OU=Students

 

 

 

Edit: If you want to include the DC sections as well, just adjust the grep:
egrep "^OU=|^DC="

View solution in original post

GabeShack
Valued Contributor III

PERFECT!!!

Now I have a script that will name machines as people log into them!

Full finished script below:

 

#!/bin/sh 

USERNAME="$4" 
PASSWORD="$5" 
JAMF_URL="$6" 
EA_NAME="$7" 
UUID=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformUUID/{print $4}') 
LDAP_EA_VALUE=$(/usr/bin/curl -H "Accept: application/xml" -su "$USERNAME:$PASSWORD" "${JAMF_URL}/JSSResource/computers/udid/${UUID}/subset/extension_attributes" | xpath -e "//extension_attribute[name='$EA_NAME']" 2>/dev/null | xmllint --format - | awk -F'>|<' '/<value>/{print $3}')
OU_VALUES=$(/bin/echo "$LDAP_EA_VALUE" | tr ',' '\n' | grep "^OU=" | tr '\n' ' ')
ASSETTAG=$(/usr/bin/curl -H "Accept: application/xml" -su "$USERNAME:$PASSWORD" "${JAMF_URL}/JSSResource/computers/udid/${UUID}/subset/general" | xmllint --format - 2>/dev/null | awk -F'>|<' '/<asset_tag>/{print $3}')
BUILDING=$(if grep -q "PHS" <<< "$OU_VALUES"]; 
then echo "HS"  
fi
if grep -q "JW" <<< "$OU_VALUES"]; 
then echo "MS"  
fi
if grep -q "CP" <<< "$OU_VALUES"]; 
then echo "CP"  
fi
if grep -q "RS" <<< "$OU_VALUES"]; 
then echo "RS"  
fi
if grep -q "JP" <<< "$OU_VALUES"]; 
then echo "JP"  
fi
if grep -q "LB" <<< "$OU_VALUES"]; 
then echo "LB"
fi
if grep -q "VR" <<< "$OU_VALUES"]; 
then echo "VR"  
fi
if grep -q "PMS" <<< "$OU_VALUES"]; 
then echo "MS"  
fi
if grep -q "MS" <<< "$OU_VALUES"]; 
then echo "MS"  
fi)
POSITION=$(if grep -q "Students" <<< "$OU_VALUES"]; 
then echo "-Student" 
else echo "-Teacher" 
fi)
COMPUTERNAME="$BUILDING""$POSITION""$ASSETTAG"

/usr/sbin/scutil --set ComputerName "${COMPUTERNAME}"
/usr/sbin/scutil --set LocalHostName "${COMPUTERNAME}"
/usr/sbin/scutil --set HostName "${COMPUTERNAME}"

dscacheutil -flushcache

echo "Computer name has been set to "${COMPUTERNAME}""

jamf recon
exit 0

 

Gabe Shackney
Princeton Public Schools

View solution in original post

mm2270
Legendary Contributor II

Hey @GabeShack One possible way to solve your issue would be to find what the highest UID is of local accounts above 500, since I'm assuming that the account you're interested in is the most recently created account and will therefore have the highest UID in that range. Meaning, it would have a 501, or 502, etc UID.

If this whole process is supposed to be running on newly set up Macs, then it shouldn't be hard to get the username with something like that. I'm assuming that's the case, right?

highest_uid=$(/usr/bin/dscl . list /Users UniqueID | /usr/bin/awk '$2 > 500 {print $2}' | /usr/bin/sort -n | /usr/bin/tail -1)

Then with the highest UID value on hand, you can use dscl again to search the local directory for that user and extract the username.

current_user=$(/usr/bin/dscl . search /Users UniqueID $highest_uid | /usr/bin/awk '{print $1; exit}')

 

View solution in original post

24 REPLIES 24

GabeShack
Valued Contributor III

So I found this 

dscl /Active Directory/MyDomain/All Domains -read Users/${user}
 
which if i put in my AD info and the “current user” i get a ton of info which includes OU for that user, which can tell me if there are at least student or faculty.  Then this same response tells me building and also tells me grade level.
 
My edit is below, but can add the line to include the "grab current user" info after the login happens.
dscl /Active Directory/MYDOMAIN/All Domains -read Users/MYUSERNAME
 
This is the entry in AD that we need to grab: dsAttrTypeNative:distinguishedName:
CN=Test Student01,OU=6,OU=MS,OU=Students,DC=MYDOMAIN,DC=org
This gives us the student OU, the grade OU, and the Building OU and wether they are a teacher or student  OU. 
 
So to me we can maybe just call this one line, however here is the problem, this lookup command wont work since we wouldn’t be to binding the new machines, so im wondering if we can pull this line from the JIM or jamf connect somehow?
 
Anyone have any thoughts? @mm2270 lol you are the wizard of this kinda thing...

 

Gabe Shackney
Princeton Public Schools

mm2270
Legendary Contributor II

Hey @GabeShack I'll see if I can help. But you mentioned that your Macs won't be joined to AD when running any lookups. If that's the case, it will be harder to get this information directly. I'm honestly not sure if there's some way to get this info our of JIM.

One question I have is, when you do the dscl /Active Directory/MyDomain/All Domains -read Users/${user} command right now, the ${user} string must be matching an existing user in AD. Are the account names for the students and faculty being auto generated on enrollment by some kind of lookup right now, or as part of the automated device enrollment process? I'm guessing it must be pulling that out of AD when they get the Mac assigned, correct?

Edit: Nevermind. I see you mention Jamf Connect, so I'm assuming they are signing in with an account on the Jamf Connect screen that creates the account for them.

If there is no AD bind on the Macs, then another option is to use something like ldapsearch, but the syntax for that is a bit more complicated, plus you have to provide it with some credentials to do the "bind on the fly" connection to Active Directory, including a full distinguished name for that account, usually.

If using ldapsearch interests you, I can lookup some old scripts where I've used it and post the example here.

GabeShack
Valued Contributor III

@mm2270 Thanks for the reply!

correct. The whole point of us getting JAMF connect was to move away from the binding. That’s also why I wanted to redo our current imaging process to include the JAMF connect login with the DEPNotify option (probably how I’ll trigger this and other specific policies) and make a real no touch solution vs what we do currently which is each building tech has to physically name each machine (with dep notify running on an admin user before it reboots to let the end user log in the first time). 


LDAPsearch is fine and I can have it authenticate with an user account that has access (I’m assuming I can have that be a variable in the script) and timing is key so my logistical thoughts are:

1.  user logs in with JAMF connect to azure login

2. A recon triggers the assignment of the user to the device to grab the newly created user’s extra ldap details from the JIM and adds it to the record in the JSS. 

3.  A script immediately runs that looks up the user OU info and greps the specifics listed above (building code, whether staff or student OU, etc.) The script also grabs the JSS inventory asset tag info (which I think I already have a script for somewhere lol, and the asset tag info is all in the inventory pre load csv) then it applies the name based on those specifics:

IE

(Building-TeacherOrStudent-assettag#)

HS-Student12345

MS-Teacher67891

(I think I’m going to forgot about adding the admin part for now and figure something out later since there isn’t a great ou or security group for this right now). 

 

Gabe Shackney
Princeton Public Schools

GabeShack
Valued Contributor III

@mm2270 

Per my JAMF customer success rep, Trying a different approach.  I put in an extension attribute to grab the info using the ldap attribute mapping feature which grabs that string of info for the attribute I listed above.  Now I would just need to make a command to take this info out of the JSS to grep the info that is returned below.  First result is a student 2nd result is a faculty member.  For students it returns their building and grade levels.  For faculty, it gives the building and faculty info and skips grade info.

Name, Grade, Building, Teacher/Student:CN=George Smith,OU=11,OU=PHS,OU=Students,DC=MYDOMAIN,DC=org 

Name, Grade, Building, Teacher/Student:CN=Ellen Smith,OU=CP,OU=Faculty,DC=MYDOMAIN,DC=org

So this is probably easier to grab from the JSS without having to do the "bind on fly" stuff.

Gabe Shackney
Princeton Public Schools

mm2270
Legendary Contributor II

Ah, yes, that actually makes more sense. I sometimes forget that LDAP Extension Attributes are a thing. I don't use them often, but this seems like a good fit for what you're after.

So I think once you have your LDAP EAs in place, you'll have to use the API to grab that info from the computer record.

mm2270
Legendary Contributor II

Something like this maybe?

#!/bin/sh

USERNAME="$4"
PASSWORD="$5"
JAMF_URL="https://your.jamf.server.com"

EA_NAME="Name of LDAP EA"

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

LDAP_EA_VALUE=$(/usr/bin/curl -H "Accept: application/xml" -su "$USERNAME:$PASSWORD" "${JAMF_URL}/JSSResource/computers/udid/${UUID}/subset/extension_attributes" | xpath -e "//extension_attribute[name='$EA_NAME']" 2>/dev/null | xmllint --format - | awk -F'>|<' '/<value>/{print $3}')

GabeShack
Valued Contributor III

So once that returns the info for the values, I would still need to make logic to determine if staff or student (basically if the value has "student" then name computer student).  Then grep the building name out of the value (in the student case either PHS=HS or JW=MS)  (in the case of teachers it would have to be one of our 4 elementary school abbreviations which can remain as is CP,JP,LB,RS or PHS=HS or JW=MS).  Then the last step is grabbing the asset tag, which I think I can find the script for.   Last step would be to put it all together to form the correct name which would be HS-Teacher12345  or MS-Student12345.

Thanks @mm2270 this helps get me closer.  Its the logic now that I need to work on.

Edit:

So I'm playing with the variables and how to grab the info for the computer name and figure adding something like the following:

 

 

COMPUTERNAME="$BUILDING$POSITION$ASSETTAG"
BUILDING=$()
#POSITION=$(if [[ $LDAP_EA_VALUE == *"Students"* ]]; then echo "-Student" else echo "-Teacher")

POSITION=$(if grep -q "Students" <<< "$LDAP_EA_VALUE"]; 
then echo "-Student" 
else echo "-Teacher" 
fi)

 

EDIT:

First part didn't seem to work, the 2nd one there with the grep is working.

Just need to figure out the building part then and grabbing that specific info from the following ea returns which in the below would either be PHS or CP:

Name, Grade, Building, Teacher/Student:CN=George Smith,OU=11,OU=PHS,OU=Students,DC=MYDOMAIN,DC=org 

Name, Grade, Building, Teacher/Student:CN=Ellen Smith,OU=CP,OU=Faculty,DC=MYDOMAIN,DC=org

 

Gabe Shackney
Princeton Public Schools

GabeShack
Valued Contributor III

@mm2270 So I have a clunky way to grab the building OU but it will work for my purposes, however I had the realization below that if the username contains any of these letters together, it will output the wrong building from the below script.  Is there a way I could add a piece to ignore any text before the first comma on the below?

 

BUILDING=$(if grep -q "PHS" <<< "$LDAP_EA_VALUE"]; 
then echo "HS"  
fi
if grep -q "JW" <<< "$LDAP_EA_VALUE"]; 
then echo "MS"  
fi
if grep -q "CP" <<< "$LDAP_EA_VALUE"]; 
then echo "CP"  
fi
if grep -q "RS" <<< "$LDAP_EA_VALUE"]; 
then echo "RS"  
fi
if grep -q "JP" <<< "$LDAP_EA_VALUE"]; 
then echo "JP"  
fi
if grep -q "LB" <<< "$LDAP_EA_VALUE"]; 
then echo "LB"
fi
if grep -q "VR" <<< "$LDAP_EA_VALUE"]; 
then echo "VR"  
fi)

 

My CSM gave me this for just grabbing the exact value, however 3 buildings would need to be renamed and the results for students and faculty also have the building OU in a different position so  his example would need more logic as well:

 

"CN=George Smith,OU=11,OU=PHS,OU=Students,DC=Princetonk12,DC=org"
 
echo $LDAP_EA_VALUE | cut -d "," -f3 | cut -c 4-

 

 This one returns PHS for students and returns Faculty for Faculty, so it would have to be based on the student or faculty pull.

So here is my full script that in testing works so far, (unless one of the building abbreviations appears in the users name).  I've just hashed out the actual naming portion until i can ignore the usernames in my extension attribute (ignore anything before the first comma in my grep result).

 

#!/bin/sh 

USERNAME="$4" 
PASSWORD="$5" 
JAMF_URL="$6" 
EA_NAME="$7" 
UUID=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformUUID/{print $4}') 
LDAP_EA_VALUE=$(/usr/bin/curl -H "Accept: application/xml" -su "$USERNAME:$PASSWORD" "${JAMF_URL}/JSSResource/computers/udid/${UUID}/subset/extension_attributes" | xpath -e "//extension_attribute[name='$EA_NAME']" 2>/dev/null | xmllint --format - | awk -F'>|<' '/<value>/{print $3}')
ASSETTAG=$(/usr/bin/curl -H "Accept: application/xml" -su "$USERNAME:$PASSWORD" "${JAMF_URL}/JSSResource/computers/udid/${UUID}/subset/general" | xmllint --format - 2>/dev/null | awk -F'>|<' '/<asset_tag>/{print $3}')
BUILDING=$(if grep -q "PHS" <<< "$LDAP_EA_VALUE"]; 
then echo "HS"  
fi
if grep -q "JW" <<< "$LDAP_EA_VALUE"]; 
then echo "MS"  
fi
if grep -q "CP" <<< "$LDAP_EA_VALUE"]; 
then echo "CP"  
fi
if grep -q "RS" <<< "$LDAP_EA_VALUE"]; 
then echo "RS"  
fi
if grep -q "JP" <<< "$LDAP_EA_VALUE"]; 
then echo "JP"  
fi
if grep -q "LB" <<< "$LDAP_EA_VALUE"]; 
then echo "LB"
fi
if grep -q "VR" <<< "$LDAP_EA_VALUE"]; 
then echo "VR"  
fi)
POSITION=$(if grep -q "Students" <<< "$LDAP_EA_VALUE"]; 
then echo "-Student" 
else echo "-Teacher" 
fi)
COMPUTERNAME="$BUILDING""$POSITION""$ASSETTAG"

#/usr/sbin/scutil --set ComputerName "${COMPUTERNAME}"
#/usr/sbin/scutil --set LocalHostName "${COMPUTERNAME}"
#/usr/sbin/scutil --set HostName "${COMPUTERNAME}"

#dscacheutil -flushcache

#echo "Computer name has been set to "${COMPUTERNAME}""
#echo "<result>scutil --get ComputerName</result>"
echo "$COMPUTERNAME"
#echo $LDAP_EA_VALUE | cut -d "," -f3 | cut -c 4-

#jamf recon
exit 0

 

Gabe Shackney
Princeton Public Schools

mm2270
Legendary Contributor II

That seems like the perfect use case for a case statement (no pun intended) Rather than all those if/then/else blocks, consider using something like this

 

 

case "$LDAP_EA_VALUE" in
	*PHS*)
	BUILDING="HS" ;;
	*JW*)
	BUILDING="MS" ;;
	*CP*)
	BUILDING="CP" ;;
	*RS*)
	BUILDING="RS" ;;
	*JP*)
	BUILDING="JP" ;;
	*LB*)
	BUILDING="LB" ;;
	*VR*)
	BUILDING="VR" ;;
esac

 

GabeShack
Valued Contributor III

 

@mm2270 Thanks!

Is there a way to make this command only show everything after the first comma in the return?

LDAP_EA_VALUE=$(/usr/bin/curl -H "Accept: application/xml" -su "$USERNAME:$PASSWORD" "${JAMF_URL}/JSSResource/computers/udid/${UUID}/subset/extension_attributes" | xpath -e "//extension_attribute[name='$EA_NAME']" 2>/dev/null | xmllint --format - | awk -F'>|<' '/<value>/{print $3}')

 

Gabe Shackney
Princeton Public Schools

mm2270
Legendary Contributor II

See my reply above, from just a few moments ago 😊

mm2270
Legendary Contributor II

Sorry @GabeShack It just occurred to me you asked about avoiding a false positive based on possible student or faculty usernames. You could try doing something like this to reformat the string to only include the "OU" items and exclude the "CN" and "DC" sections

 

OU_VALUES=$(/bin/echo "$LDAP_EA_VALUE" | tr ',' '\n' | grep "^OU=" | tr '\n' ' ')

 

The above would produce the following string to use in the case statement or your original if/then/else grep script.

 

OU=11 OU=PHS OU=Students

 

 

 

Edit: If you want to include the DC sections as well, just adjust the grep:
egrep "^OU=|^DC="

GabeShack
Valued Contributor III

PERFECT!!!

Now I have a script that will name machines as people log into them!

Full finished script below:

 

#!/bin/sh 

USERNAME="$4" 
PASSWORD="$5" 
JAMF_URL="$6" 
EA_NAME="$7" 
UUID=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformUUID/{print $4}') 
LDAP_EA_VALUE=$(/usr/bin/curl -H "Accept: application/xml" -su "$USERNAME:$PASSWORD" "${JAMF_URL}/JSSResource/computers/udid/${UUID}/subset/extension_attributes" | xpath -e "//extension_attribute[name='$EA_NAME']" 2>/dev/null | xmllint --format - | awk -F'>|<' '/<value>/{print $3}')
OU_VALUES=$(/bin/echo "$LDAP_EA_VALUE" | tr ',' '\n' | grep "^OU=" | tr '\n' ' ')
ASSETTAG=$(/usr/bin/curl -H "Accept: application/xml" -su "$USERNAME:$PASSWORD" "${JAMF_URL}/JSSResource/computers/udid/${UUID}/subset/general" | xmllint --format - 2>/dev/null | awk -F'>|<' '/<asset_tag>/{print $3}')
BUILDING=$(if grep -q "PHS" <<< "$OU_VALUES"]; 
then echo "HS"  
fi
if grep -q "JW" <<< "$OU_VALUES"]; 
then echo "MS"  
fi
if grep -q "CP" <<< "$OU_VALUES"]; 
then echo "CP"  
fi
if grep -q "RS" <<< "$OU_VALUES"]; 
then echo "RS"  
fi
if grep -q "JP" <<< "$OU_VALUES"]; 
then echo "JP"  
fi
if grep -q "LB" <<< "$OU_VALUES"]; 
then echo "LB"
fi
if grep -q "VR" <<< "$OU_VALUES"]; 
then echo "VR"  
fi
if grep -q "PMS" <<< "$OU_VALUES"]; 
then echo "MS"  
fi
if grep -q "MS" <<< "$OU_VALUES"]; 
then echo "MS"  
fi)
POSITION=$(if grep -q "Students" <<< "$OU_VALUES"]; 
then echo "-Student" 
else echo "-Teacher" 
fi)
COMPUTERNAME="$BUILDING""$POSITION""$ASSETTAG"

/usr/sbin/scutil --set ComputerName "${COMPUTERNAME}"
/usr/sbin/scutil --set LocalHostName "${COMPUTERNAME}"
/usr/sbin/scutil --set HostName "${COMPUTERNAME}"

dscacheutil -flushcache

echo "Computer name has been set to "${COMPUTERNAME}""

jamf recon
exit 0

 

Gabe Shackney
Princeton Public Schools

GabeShack
Valued Contributor III

Btw all of this could be avoided if JAMF and apple would make a proper naming during enrollment piece like what used to exist in the days of Casper Imaging and still does with mobile devices. 

Gabe Shackney
Princeton Public Schools

GabeShack
Valued Contributor III

@mm2270 Thanks again for your help with this.  I'm however seeing a couple of issues when running this from the Connect Notify window.

I added a 

currentUser=$(/bin/ls -l /dev/console | /usr/bin/awk '{print $3}')
jamf recon -endUsername $currentUser

To the top, however I think its not finding the logged in user since the login window hasn't completed while Connect Notify is running.  Is there another way to pull the name of the user that has a user folder (because at this point I'm pretty sure the user folder had been created)? Also at this point the enrollment hasn't created our local admin user yet, so it is just showing the 1 person as having a user folder, so might be easier to assign the username based on that folder.

Another error Im getting running the above script during the connect notify window is below.  I'm wondering if scutil has issues running from the login window or if this is just because it cannot grab a legit user name at the start (actually in just reading this over it is all from the name not getting set correctly since the computer name will now start with -Teacher I think scutil is thinking im telling it to --T something lol).  So actually that just makes me need to rethink the first part of assigning the username to the device and pulling the correct username and not _mbSetup or root:

Script result: Retrieving inventory preferences from https://princetonk12.jamfcloud.com/...
Locating hard drive information...
Finding extension attributes...
Locating applications...
Searching path: /Applications
Locating package receipts...
Locating accounts...
Locating software updates...
Locating printers...
Gathering application usage information from the JamfDaemon...
Searching path: /System/Applications
Searching path: /Users
Locating hardware information (macOS 11.6.3)...
Submitting data to https://mydomain.jamfcloud.com/...
<computer_id>4953</computer_id>
scutil: invalid option -- T
usage: /usr/sbin/scutil
	interactive access to the dynamic store.

   or: /usr/sbin/scutil --prefs [preference-file]
	interactive access to the [raw] stored preferences.

   or: /usr/sbin/scutil [-W] -r nodename
   or: /usr/sbin/scutil [-W] -r address
   or: /usr/sbin/scutil [-W] -r local-address remote-address
	check reachability of node, address, or address pair (-W to "watch").

   or: /usr/sbin/scutil -w dynamic-store-key [ -t timeout ]
	-w	wait for presense of dynamic store key
	-t	time to wait for key

   or: /usr/sbin/scutil --get pref
   or: /usr/sbin/scutil --set pref [newval]
   or: /usr/sbin/scutil --get filename path key  
	pref	display (or set) the specified preference.  Valid preferences
		include:
			ComputerName, LocalHostName, HostName
	newval	New preference value to be set.  If not specified,
		the new value will be read from standard input.

   or: /usr/sbin/scutil --dns
	show DNS configuration.

   or: /usr/sbin/scutil --proxy
	show "proxy" configuration.

   or: /usr/sbin/scutil --nwi
	show network information

   or: /usr/sbin/scutil --nc
	show VPN network configuration information. Use --nc help for full command list

   or: /usr/sbin/scutil --allow-new-interfaces [off|on]
	manage new interface creation with screen locked.

   or: /usr/sbin/scutil --error err#
	display a descriptive message for the given error code
scutil: invalid option -- T
usage: /usr/sbin/scutil
	interactive access to the dynamic store.

   or: /usr/sbin/scutil --prefs [preference-file]
	interactive access to the [raw] stored preferences.

   or: /usr/sbin/scutil [-W] -r nodename
   or: /usr/sbin/scutil [-W] -r address
   or: /usr/sbin/scutil [-W] -r local-address remote-address
	check reachability of node, address, or address pair (-W to "watch").

   or: /usr/sbin/scutil -w dynamic-store-key [ -t timeout ]
	-w	wait for presense of dynamic store key
	-t	time to wait for key

   or: /usr/sbin/scutil --get pref
   or: /usr/sbin/scutil --set pref [newval]
   or: /usr/sbin/scutil --get filename path key  
	pref	display (or set) the specified preference.  Valid preferences
		include:
			ComputerName, LocalHostName, HostName
	newval	New preference value to be set.  If not specified,
		the new value will be read from standard input.

   or: /usr/sbin/scutil --dns
	show DNS configuration.

   or: /usr/sbin/scutil --proxy
	show "proxy" configuration.

   or: /usr/sbin/scutil --nwi
	show network information

   or: /usr/sbin/scutil --nc
	show VPN network configuration information. Use --nc help for full command list

   or: /usr/sbin/scutil --allow-new-interfaces [off|on]
	manage new interface creation with screen locked.

   or: /usr/sbin/scutil --error err#
	display a descriptive message for the given error code
scutil: invalid option -- T
usage: /usr/sbin/scutil
	interactive access to the dynamic store.

   or: /usr/sbin/scutil --prefs [preference-file]
	interactive access to the [raw] stored preferences.

   or: /usr/sbin/scutil [-W] -r nodename
   or: /usr/sbin/scutil [-W] -r address
   or: /usr/sbin/scutil [-W] -r local-address remote-address
	check reachability of node, address, or address pair (-W to "watch").

   or: /usr/sbin/scutil -w dynamic-store-key [ -t timeout ]
	-w	wait for presense of dynamic store key
	-t	time to wait for key

   or: /usr/sbin/scutil --get pref
   or: /usr/sbin/scutil --set pref [newval]
   or: /usr/sbin/scutil --get filename path key  
	pref	display (or set) the specified preference.  Valid preferences
		include:
			ComputerName, LocalHostName, HostName
	newval	New preference value to be set.  If not specified,
		the new value will be read from standard input.

   or: /usr/sbin/scutil --dns
	show DNS configuration.

   or: /usr/sbin/scutil --proxy
	show "proxy" configuration.

   or: /usr/sbin/scutil --nwi
	show network information

   or: /usr/sbin/scutil --nc
	show VPN network configuration information. Use --nc help for full command list

   or: /usr/sbin/scutil --allow-new-interfaces [off|on]
	manage new interface creation with screen locked.

   or: /usr/sbin/scutil --error err#
	display a descriptive message for the given error code
Computer name has been set to -Teacher32107
Retrieving inventory preferences from https://princetonk12.jamfcloud.com/...
Locating hard drive information...
Finding extension attributes...
Locating accounts...
Locating package receipts...
Locating applications...
Searching path: /Applications
Locating software updates...
Locating printers...
Gathering application usage information from the JamfDaemon...
Searching path: /System/Applications
Searching path: /Users
Locating hardware information (macOS 11.6.3)...
Submitting data to https://mydomain.jamfcloud.com/...
<computer_id>4953</computer_id>

 

Gabe Shackney
Princeton Public Schools

mm2270
Legendary Contributor II

Hey @GabeShack One possible way to solve your issue would be to find what the highest UID is of local accounts above 500, since I'm assuming that the account you're interested in is the most recently created account and will therefore have the highest UID in that range. Meaning, it would have a 501, or 502, etc UID.

If this whole process is supposed to be running on newly set up Macs, then it shouldn't be hard to get the username with something like that. I'm assuming that's the case, right?

highest_uid=$(/usr/bin/dscl . list /Users UniqueID | /usr/bin/awk '$2 > 500 {print $2}' | /usr/bin/sort -n | /usr/bin/tail -1)

Then with the highest UID value on hand, you can use dscl again to search the local directory for that user and extract the username.

current_user=$(/usr/bin/dscl . search /Users UniqueID $highest_uid | /usr/bin/awk '{print $1; exit}')

 

GabeShack
Valued Contributor III

@mm2270 Yup perfect and correct!
It’s most likely going to be the 501 user each time.  The local admin user seems to get 502 when and if it’s created.  

I think I found a bug though with JAMF and the prestage admin account creation. I’ve had at least two times, (in my repetitive wiping and re enrolling/testing) where the local admin account never got created. I still have the management account, but the local admin just isn’t there. It’s weird. 

Anyway, thanks for this. I believe that will work. Will test tomorrow. 

Gabe Shackney
Princeton Public Schools

GabeShack
Valued Contributor III

Hey @mm2270 

I'm seeing an issue, and Im guessing its a timing piece.  It looks like the extension attribute lookup isn't happening in the given timeframe in some cases which leaves that field blank before the naming script runs.  This keeps the machine from getting the OU info which is then keeping the naming from happening.  

 

The other guess I have is maybe something in 12.3.1 or jamf connect 2.10 changed the timing of the user folder creation, so that by the beginning of the lookup of the last created user folder is not finding anything.

 

I have the copied error of the script below not sure if it really tells us anything though.

Wondering if you know of a way to tell it to wait until a true user is created (not the Jamf Management user).

 

(Actually I just realized that since its not grabbing a building name, that its just sticking a - in front of teacher and it thinks its trying to type another command).

Script result: Retrieving inventory preferences from https://domain.jamfcloud.com/...
Finding extension attributes...
Locating applications...
Locating package receipts...
Locating hard drive information...
Locating accounts...
Searching path: /Applications
Locating printers...
Gathering application usage information from the JamfDaemon...
Searching path: /System/Applications
Searching path: /Users
Locating hardware information (macOS 12.3.1)...
Submitting data to https://domain.jamfcloud.com/...
<computer_id>5200</computer_id>
scutil: invalid option -- T
usage: /usr/sbin/scutil
	interactive access to the dynamic store.

   or: /usr/sbin/scutil --prefs [preference-file]
	interactive access to the [raw] stored preferences.

   or: /usr/sbin/scutil [-W] -r nodename
   or: /usr/sbin/scutil [-W] -r address
   or: /usr/sbin/scutil [-W] -r local-address remote-address
	check reachability of node, address, or address pair (-W to "watch").

   or: /usr/sbin/scutil -w dynamic-store-key [ -t timeout ]
	-w	wait for presense of dynamic store key
	-t	time to wait for key

   or: /usr/sbin/scutil --get pref
   or: /usr/sbin/scutil --set pref [newval]
   or: /usr/sbin/scutil --get filename path key  
	pref	display (or set) the specified preference.  Valid preferences
		include:
			ComputerName, LocalHostName, HostName
	newval	New preference value to be set.  If not specified,
		the new value will be read from standard input.

   or: /usr/sbin/scutil --dns
	show DNS configuration.

   or: /usr/sbin/scutil --proxy
	show "proxy" configuration.

   or: /usr/sbin/scutil --nwi
	show network information

   or: /usr/sbin/scutil --nc
	show VPN network configuration information. Use --nc help for full command list

   or: /usr/sbin/scutil --allow-new-interfaces [off|on]
	manage new interface creation with screen locked.

   or: /usr/sbin/scutil --error err#
	display a descriptive message for the given error code
scutil: invalid option -- T
usage: /usr/sbin/scutil
	interactive access to the dynamic store.

   or: /usr/sbin/scutil --prefs [preference-file]
	interactive access to the [raw] stored preferences.

   or: /usr/sbin/scutil [-W] -r nodename
   or: /usr/sbin/scutil [-W] -r address
   or: /usr/sbin/scutil [-W] -r local-address remote-address
	check reachability of node, address, or address pair (-W to "watch").

   or: /usr/sbin/scutil -w dynamic-store-key [ -t timeout ]
	-w	wait for presense of dynamic store key
	-t	time to wait for key

   or: /usr/sbin/scutil --get pref
   or: /usr/sbin/scutil --set pref [newval]
   or: /usr/sbin/scutil --get filename path key  
	pref	display (or set) the specified preference.  Valid preferences
		include:
			ComputerName, LocalHostName, HostName
	newval	New preference value to be set.  If not specified,
		the new value will be read from standard input.

   or: /usr/sbin/scutil --dns
	show DNS configuration.

   or: /usr/sbin/scutil --proxy
	show "proxy" configuration.

   or: /usr/sbin/scutil --nwi
	show network information

   or: /usr/sbin/scutil --nc
	show VPN network configuration information. Use --nc help for full command list

   or: /usr/sbin/scutil --allow-new-interfaces [off|on]
	manage new interface creation with screen locked.

   or: /usr/sbin/scutil --error err#
	display a descriptive message for the given error code
scutil: invalid option -- T
usage: /usr/sbin/scutil
	interactive access to the dynamic store.

   or: /usr/sbin/scutil --prefs [preference-file]
	interactive access to the [raw] stored preferences.

   or: /usr/sbin/scutil [-W] -r nodename
   or: /usr/sbin/scutil [-W] -r address
   or: /usr/sbin/scutil [-W] -r local-address remote-address
	check reachability of node, address, or address pair (-W to "watch").

   or: /usr/sbin/scutil -w dynamic-store-key [ -t timeout ]
	-w	wait for presense of dynamic store key
	-t	time to wait for key

   or: /usr/sbin/scutil --get pref
   or: /usr/sbin/scutil --set pref [newval]
   or: /usr/sbin/scutil --get filename path key  
	pref	display (or set) the specified preference.  Valid preferences
		include:
			ComputerName, LocalHostName, HostName
	newval	New preference value to be set.  If not specified,
		the new value will be read from standard input.

   or: /usr/sbin/scutil --dns
	show DNS configuration.

   or: /usr/sbin/scutil --proxy
	show "proxy" configuration.

   or: /usr/sbin/scutil --nwi
	show network information

   or: /usr/sbin/scutil --nc
	show VPN network configuration information. Use --nc help for full command list

   or: /usr/sbin/scutil --allow-new-interfaces [off|on]
	manage new interface creation with screen locked.

   or: /usr/sbin/scutil --error err#
	display a descriptive message for the given error code
Computer name has been set to -Teacher32093
Retrieving inventory preferences from https://princetonk12.jamfcloud.com/...
Finding extension attributes...
Locating accounts...
Locating package receipts...
Locating applications...
Searching path: /Applications
Locating hard drive information...
Locating printers...
Gathering application usage information from the JamfDaemon...
Searching path: /System/Applications
Searching path: /Users
Locating hardware information (macOS 12.3.1)...
Submitting data to https://domain.jamfcloud.com/...
<computer_id>5200</computer_id>

 

Gabe Shackney
Princeton Public Schools

mm2270
Legendary Contributor II

Hey @GabeShack I can't be sure of this since I don't use Jamf Connect, and don't have a way to verify, but I believe that LDAP Extension Attribute would be getting populated during a recon, just like any other Extension Attribute. If so, would it help to add a /usr/local/bin/jamf recon to the beginning of the script somewhere, before any of the API calls happen to grab the value?

I could be oversimplifying it, but I would give that a try to see if it solves your issue. I went back to look over your last version of the script and I don't see anyplace where it's pulling a recon except at the end.

GabeShack
Valued Contributor III

@mm2270 I think it used to pull the recon with the naming piece.  However it looks like the recon is not populating the extension attribute in the same way as it used to.  I'll have to play a little with timing and or adding another recon.  Wondering if I can tell the script to loop if the EA is blank...

jamf recon -endUsername $currentUser

 

Gabe Shackney
Princeton Public Schools

GabeShack
Valued Contributor III

@mm2270 Is there an easy way for this command to throw an error if it doesn't find either teacher or student in the OU listing?

POSITION=$(if grep -q "Students" <<< "$OU_VALUES"]; 
then echo "Student"
fi
if grep -q "Teacher" <<< "$OU_VALUES"];
then echo "Teacher" 
fi)

 That way i get an error email for any that fail this script.  It will still continue on and at least name the device with just the asset tag, but otherwise I'll get alerted that the script "failed".

Gabe Shackney
Princeton Public Schools

mm2270
Legendary Contributor II

@GabeShack Try something like this.

POSITION=$(if grep -q "Students" <<< "$OU_VALUES"]; 
	then echo "Student"
elif grep -q "Teacher" <<< "$OU_VALUES"];
	then echo "Teacher" 
else
	echo ""
fi)

if [ -z "$POSITION" ]; then
	echo "No value found for POSITION"
	exit 1
fi

 

GabeShack
Valued Contributor III

@mm2270 Sorry to keep pestering you...but is there a good way to use the last command you sent to tell it to run again from the top of the script if no OU info is returned instead of an exit 1?  I keep going back and forth on exiting out or just looping it until I get a result.

Gabe Shackney
Princeton Public Schools

mm2270
Legendary Contributor II

@GabeShack Hi. So, you would probably have to contain most of the relevant commands that you want to run again into a function. Then call the function and within the function itself, check the result. If it's not what you expect, you can call the function again.

Below is an example, but you would need to move the start of the function up further in the script. Probably right after you get the device identifier for calling the API, but before the first API call.

 

function getPosition ()
{

POSITION=$(if grep -q "Students" <<< "$OU_VALUES"]; 
	then echo "Student"
elif grep -q "Teacher" <<< "$OU_VALUES"];
	then echo "Teacher" 
else
	echo ""
fi)

if [ -z "$POSITION" ]; then
	echo "No value found for POSITION"
	getPosition
fi

}

## Call the function to start the process
getPosition

 

Let me know if you need more help with this after giving it a shot.

One important thing to keep in mind when using this kind of loop. If for some reason it just can't get the position information, you'll be stuck in an unbreakable loop since the script will just dutifully keep running the function over and over again until the machine dies.

If that's a concern, you could put a count somewhere within this loop that on each run it increments, until it reaches a certain value. Say 10 times before it gives up.