Posted on 07-14-2020 02:02 PM
I've been trying to adapt our computer naming script to wait for input from the user by cobbling together information fromhere and here and probably a few others, I can't seem to get it to work.
I just can't seem to figure out what I'm doing wrong, maybe there's an easier way? Can someone take a crack at it?
Original script that works (however if someone's not staring at the screen and they miss the prompts, then the names get messed up)
Also, if you can happen to fix the part at the top I commented out that looked at the machine type (laptop/desktop) and automatically puts in the correct type - that would be awesome :).
identifying data in script removed due to internal security requirements - but scrubbed version below retains the syntax and just made generic
#!/bin/bash
set -x
# jamf recon
loggedInUser=$(stat -f%Su /dev/console)
loggedInUID=$(id -u $loggedInUser)
if [[ "$loggedInUser" != "root" ]] && [[ "$loggedInUser" != "_mbsetup" ]]; then
## Create local script
cat << EOD > /private/tmp/computerrenamescript.sh
#!/bin/bash
TT=$(/usr/bin/osascript -e 'tell application "System Events" to set MacTYPE to text returned of (display dialog "Please input the machine type - MD = Mac Desktop or ML = Mac Laptop" default answer "" with icon 2)')
#ModelType=$(system_profiler SPHardwareDataType | grep 'Model Name:' | awk '{ print $3 }')
#echo "$ModelType"
#if [[ "$ModelType" == "MacBook" ]]; then
# TT=ML
#else
# TT=MD
#fi
BB=$(/usr/bin/osascript -e 'tell application "System Events" to set BRAND to text returned of (display dialog "Please input the brand - AA = AA, AB = AB, AC = AC," default answer "" with icon 2)')
LL=$(/usr/bin/osascript -e 'tell application "System Events" to set MacLoc to text returned of (display dialog "Please enter the location - BA = BA, BB = BB, BC = BC" default answer "" with icon 2)')
NN=$(/usr/bin/osascript -e 'tell application "System Events" to set DEPARTMENT to text returned of (display dialog "Please enter department - 01 = 01, 02 = 02, " default answer "" with icon 2)')
SN=$(system_profiler SPHardwareDataType | grep 'Serial Number' | awk '{print $4}' | tail -c -8) #this grabs the last 7 of the serial number
echo "${TT}${BB}${LL}${NN}${SN}" > /private/tmp/computerrenametext.txt
EOD
## Make script executable
/bin/chmod +x /private/tmp/computerrenamescript.sh
## Run the script as logged in user
/bin/launchctl asuser "$loggedInUID" sudo -iu "$loggedInUser" "/private/tmp/computerrenamescript.sh"
## Get the new name from the local file
newComputerName=$(cat /tmp/computerrenametext.txt)
if [ ! -z "$newComputerName" ]; then
echo "$newComputerName"
## Rename the computer to the new name
/usr/local/bin/jamf setComputerName -name "$newComputerName"
echo $newComputerName
scutil --set HostName $newComputerName
scutil --set LocalHostName $newComputerName
scutil --set ComputerName $newComputerName
dscacheutil -flushcache
jamf recon
## Remove local script
rm -f /private/tmp/computerrenamescript.sh
exit 0
else
echo "No name was found to rename to"
## Remove local script
rm -f /private/tmp/computerrenamescript.sh
exit 1
fi
else
echo "No-one logged in. Exiting"
exit 0
fi
Solved! Go to Solution.
Posted on 07-14-2020 09:22 PM
So, I was looking for a random post to do my #100daysofcode tonight and this was the first post that asked for script help. So, here is my Python version of this. It does not require TCC/PPPC and I tried to mimic your requirements as well as I could. Basically if you can get rid of the tell application
parts of Applescripts
in 10.14+ you can avoid a lot of the TCC/PPPC prompts.
#!/usr/bin/python
import subprocess
from SystemConfiguration import SCDynamicStoreCopyConsoleUser
import sys
import plistlib
# vars for current user
USER, UID, GID = SCDynamicStoreCopyConsoleUser(None, None, None)
# dialogs
BRAND = """
set BRAND to text returned of (display dialog "Please input the brand - AA = AA, AB = AB, AC = AC," default answer "" with title "Brand")
"""
LOCATION = """
set MacLoc to text returned of (display dialog "Please enter the location - BA = BA, BB = BB, BC = BC" default answer "" with title "Location")
"""
DEPARTMENT = """
set DEPARTMENT to text returned of (display dialog "Please enter department - 01 = 01, 02 = 02, " default answer "" with title "Department")
"""
MODEL = """
set MacTYPE to text returned of (display dialog "Please input the machine type - MD = Desktop, ML = Laptop, " default answer "" with title "Mac Model")
"""
# functions
def get_serial():
"""get last 7 characters of serial number"""
# system profiler command
cmd = ["system_profiler", "SPHardwareDataType", "-xml"]
# run the command
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate()
# load output into a var
data = plistlib.readPlistFromString(out)
# grab sreial number, mutate serail to last 7 characters
serial = data[0]["_items"][0]["serial_number"]
serial = serial[-7:]
return serial
def computer_name(name):
"""name computer function"""
# options for scutil, since macOS has 3 hostnames
options = ["HostName", "ComputerName", "LocalHostName"]
# loop through options and pass the name to set it
for option in options:
subprocess.call(["scutil", "--set", option, name])
def osascript(osastring):
"""Wrapper to run AppleScript commands"""
# command to run the applescripts
cmd = ['/usr/bin/osascript', '-e', osastring]
# execute subprocess with commands
proc = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = proc.communicate()
# test for non zero exit status
if proc.returncode != 0:
print('Error: ', err.decode('UTF-8'))
# if we get output return it
if out:
return out.decode('UTF-8').rstrip('
')
return u''
def main():
"""run the logic"""
# if at login window USER will return None
# exit if we find _mbsetupuser
if USER is not None and USER != "_mbsetupuser":
# prompt for brand
brand = osascript(BRAND).decode('utf-8')
# prompt for location
loc = osascript(LOCATION).decode('utf-8')
# prompt for department
dept = osascript(DEPARTMENT).decode('utf-8')
# get the last 7 characters of the serial number
ser = get_serial()
# prompt for model
model = osascript(MODEL).decode('utf-8')
# build the computer name
name = str(model + brand + loc + dept + ser)
# set the computer name
computer_name(name)
else:
# if at login window or _mbsetupuser found, exit
sys.exit(0)
if __name__ == "__main__":
main()
if you wanted all the characters to be uppercase too, that would be super easy to do in Python, just call .upper()
to capitalize them.
Hope this helps, and thanks for the problem so I can count this toward my #100daysofcode
Posted on 07-14-2020 04:47 PM
Hi @jwojda,
For the computer model you can use:
#Determine Mac Type
hwIdentifier=$(sysctl -n hw.model)
#Simplify the model type
if [[ "$hwIdentifier" =~ "MacBookPro" ]] ; then
modelType="MBP"
elif [[ "$hwIdentifier" =~ "MacBookAir" ]] ; then
modelType="MBA"
elif [[ "$hwIdentifier" =~ "iMac" ]] ; then
modelType="iMac"
elif [[ "$hwIdentifier" =~ "MacBook" ]] ; then
modelType="MB"
elif [[ "$hwIdentifier" =~ "Macmini" ]] ; then
modelType="MM"
elif [[ "$hwIdentifier" =~ "MacPro" ]] ; then
modelType="MP"
fi
I worked on a similar script in this thread Script: Best way to request user input.
Are there always just 3 options? It may be easier if you offer your users a dropdown menu like:
#!/bin/sh
#Applescript list to bash variable output
brandSelected=$( osascript<<APPLESCRIPT
tell application "System Events" to set selectBrand to {"AA", "AB", "AC"}
set selectBrand to choose from list selectBrand with prompt "Please input the brand - AA = AA, AB = AB, AC = AC," default items {"AA"}
selectBrand
APPLESCRIPT
)
echo $brandSelected
Posted on 07-14-2020 05:29 PM
@shaquir Thanks! I will give that a try. There are always those 4 inputs and then part of the serial number.
I can try setting up the menu, theoretically those would wait till something is selected?
Posted on 07-14-2020 07:09 PM
I'm a little confused by the local script within a script approach. Was there any other complication you ran into when you first wrote it?
Also, what's the urgency for users to update it (are they existing users that need to update the naming or new users)?
- I ask to try and determine the best approach, jamf policy/script wise, to ensure it runs when an actual user is signed in.
Posted on 07-14-2020 09:22 PM
So, I was looking for a random post to do my #100daysofcode tonight and this was the first post that asked for script help. So, here is my Python version of this. It does not require TCC/PPPC and I tried to mimic your requirements as well as I could. Basically if you can get rid of the tell application
parts of Applescripts
in 10.14+ you can avoid a lot of the TCC/PPPC prompts.
#!/usr/bin/python
import subprocess
from SystemConfiguration import SCDynamicStoreCopyConsoleUser
import sys
import plistlib
# vars for current user
USER, UID, GID = SCDynamicStoreCopyConsoleUser(None, None, None)
# dialogs
BRAND = """
set BRAND to text returned of (display dialog "Please input the brand - AA = AA, AB = AB, AC = AC," default answer "" with title "Brand")
"""
LOCATION = """
set MacLoc to text returned of (display dialog "Please enter the location - BA = BA, BB = BB, BC = BC" default answer "" with title "Location")
"""
DEPARTMENT = """
set DEPARTMENT to text returned of (display dialog "Please enter department - 01 = 01, 02 = 02, " default answer "" with title "Department")
"""
MODEL = """
set MacTYPE to text returned of (display dialog "Please input the machine type - MD = Desktop, ML = Laptop, " default answer "" with title "Mac Model")
"""
# functions
def get_serial():
"""get last 7 characters of serial number"""
# system profiler command
cmd = ["system_profiler", "SPHardwareDataType", "-xml"]
# run the command
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate()
# load output into a var
data = plistlib.readPlistFromString(out)
# grab sreial number, mutate serail to last 7 characters
serial = data[0]["_items"][0]["serial_number"]
serial = serial[-7:]
return serial
def computer_name(name):
"""name computer function"""
# options for scutil, since macOS has 3 hostnames
options = ["HostName", "ComputerName", "LocalHostName"]
# loop through options and pass the name to set it
for option in options:
subprocess.call(["scutil", "--set", option, name])
def osascript(osastring):
"""Wrapper to run AppleScript commands"""
# command to run the applescripts
cmd = ['/usr/bin/osascript', '-e', osastring]
# execute subprocess with commands
proc = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = proc.communicate()
# test for non zero exit status
if proc.returncode != 0:
print('Error: ', err.decode('UTF-8'))
# if we get output return it
if out:
return out.decode('UTF-8').rstrip('
')
return u''
def main():
"""run the logic"""
# if at login window USER will return None
# exit if we find _mbsetupuser
if USER is not None and USER != "_mbsetupuser":
# prompt for brand
brand = osascript(BRAND).decode('utf-8')
# prompt for location
loc = osascript(LOCATION).decode('utf-8')
# prompt for department
dept = osascript(DEPARTMENT).decode('utf-8')
# get the last 7 characters of the serial number
ser = get_serial()
# prompt for model
model = osascript(MODEL).decode('utf-8')
# build the computer name
name = str(model + brand + loc + dept + ser)
# set the computer name
computer_name(name)
else:
# if at login window or _mbsetupuser found, exit
sys.exit(0)
if __name__ == "__main__":
main()
if you wanted all the characters to be uppercase too, that would be super easy to do in Python, just call .upper()
to capitalize them.
Hope this helps, and thanks for the problem so I can count this toward my #100daysofcode
Posted on 07-14-2020 09:24 PM
Also, instead of prompting for Model you can probably get that in code and not prompt, but I put the prompt in since you put it in your requirements
Posted on 07-15-2020 08:29 AM
@tlarkin that's awesome, what I needed! The model I tried to do on my own but couldn't get it to work properly ever. The only other thing that I've noticed a few times is that people put in too many characters, which was causing the binding was failing due to being over 15characters total. would it be difficult to add a limit of 2 characters per input to help prevent user error?
I came across this that talks about limiting to a certain amount of characters, but the examples look like they would be in a different structure than what you had done.
Posted on 07-15-2020 08:41 AM
You found it, so Python has a built in called len()
which you can use to count instances, or characters in different data types.
>>> string = "abc123"
>>> len(string)
6
>>> if len(string) > 2:
... print("violation, can only be 2 characters")
...
violation, can only be 2 characters
Do you map LDAP users to the "User and Location" info in jamf?
Posted on 07-15-2020 09:23 AM
@tlarkin we don't, in the cloud, but don't have any of the JIM servers stood up... yet.
Posted on 07-15-2020 09:47 AM
you can use LDAP EAs to deploy user info locally via profile. So like dept, user name, email, etc.
% defaults read /Library/Managed Preferences/email.plist
{
email = "tom.larkin@acmecorp.com";
}
That is an example of something I payload to all users, so you could look at something like this and then scrape that data later on.