help with comp name script

ImAMacGuy
Valued Contributor II

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
1 ACCEPTED SOLUTION

tlarkin
Honored Contributor

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

View solution in original post

9 REPLIES 9

shaquir
Contributor III

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

ImAMacGuy
Valued Contributor II

@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?

shaquir
Contributor III

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.

tlarkin
Honored Contributor

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

tlarkin
Honored Contributor

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

ImAMacGuy
Valued Contributor II

@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.

tlarkin
Honored Contributor

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?

ImAMacGuy
Valued Contributor II

@tlarkin we don't, in the cloud, but don't have any of the JIM servers stood up... yet.

tlarkin
Honored Contributor

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.