01-04-2022 06:19 AM - edited 01-04-2022 01:08 PM
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).
Solved! Go to Solution.
01-11-2022 09:28 AM - edited 01-11-2022 09:34 AM
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="
01-11-2022 09:52 AM - edited 01-11-2022 09:56 AM
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
Posted on 01-31-2022 01:29 PM
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}')
01-05-2022 12:13 PM - edited 01-05-2022 12:33 PM
So I found this
01-05-2022 01:11 PM - edited 01-05-2022 01:13 PM
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.
01-05-2022 02:00 PM - edited 01-05-2022 02:08 PM
@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).
Posted on 01-06-2022 01:33 PM
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.
Posted on 01-06-2022 02:04 PM
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.
Posted on 01-06-2022 02:17 PM
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}')
01-10-2022 10:57 AM - edited 01-11-2022 06:55 AM
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
01-11-2022 08:49 AM - edited 01-11-2022 08:49 AM
@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
01-11-2022 09:13 AM - edited 01-11-2022 09:17 AM
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
Posted on 01-11-2022 09:18 AM
@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}')
Posted on 01-11-2022 09:29 AM
See my reply above, from just a few moments ago 😊
01-11-2022 09:28 AM - edited 01-11-2022 09:34 AM
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="
01-11-2022 09:52 AM - edited 01-11-2022 09:56 AM
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
Posted on 01-05-2022 02:23 PM
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.
Posted on 01-31-2022 01:08 PM
@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>
Posted on 01-31-2022 01:29 PM
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}')
01-31-2022 04:19 PM - edited 01-31-2022 04:21 PM
@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.
Posted on 04-22-2022 12:34 PM
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>
Posted on 04-22-2022 01:17 PM
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.
Posted on 04-22-2022 01:22 PM
@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
Posted on 04-23-2022 08:57 AM
@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".
Posted on 04-24-2022 04:32 PM
@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
04-25-2022 10:12 AM - edited 04-25-2022 10:20 AM
@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.
Posted on 04-26-2022 06:11 AM
@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.