Request for a Renaming Script

MagicMick
Contributor

Hello beloved Jamf Community.

As I'm no Scripting Expert, I humbly request if any i you could help me with the following script.

I am looking for a Self Service option where the user fills in some text (most likely an asset tag number)
Then In addition to what the user fills in, I need the following prefix to be added:

A Prefix that is set based on the Site as per Jamf Inventory (NY for macs based in New York and UK for macs based in the UK etc etc)
A Prefix that is set based on the Model of the Mac (iMac vs MB)

So as a result it should be something like

NYiMac0012345
or
UKMB0012346

Etc.

Anyone can help me with this please?

1 ACCEPTED SOLUTION

Mauricio
Contributor II

@MagicMick Big Sur, big surprises!

Apple got some changes for xpath, a good link:
https://scriptingosx.com/2020/10/dealing-with-xpath-changes-in-big-sur/

To fix your script I would recommend this:

Replace:

SITE_NAME=$(curl -H "Accept: application/xml" -sku "${API_USER}:${API_PASS}" "${JPS_URL}JSSResource/computers/udid/${UUID}/subset/general" | xpath '/computer/general/site/name/text()')

With:

SITE_NAME=$(curl -H "Accept: application/xml" -sku "${API_USER}:${API_PASS}" "${JPS_URL}JSSResource/computers/udid/${UUID}/subset/general" | xmllint --xpath '/computer/general/site/name/text()' -)

I hope this helps!

View solution in original post

9 REPLIES 9

dan-snelson
Valued Contributor II

@MagicMick The following may prove helpful

#!/bin/sh
####################################################################################################
#
# ABOUT
#
#   Rename Computer
#
####################################################################################################
#
# HISTORY
#
#   Version 1.0, 18-Jun-2015, Dan K. Snelson
#       Original version
#
####################################################################################################

jamfDisplayMessage() {
    /usr/local/jamf/bin/jamf displayMessage -message "${1}" &
}

echo "*** Rename Computer ***"

### Log current computer name
currentComputerName=$( /usr/sbin/scutil --get ComputerName )
echo "Current Computer Name: $currentComputerName"


### Prompt for new computer name
newComputerName="$(/usr/bin/osascript -e 'Tell application "System Events" to display dialog "Enter the new computer name:" default answer "" buttons {"Rename","Cancel"} default button 2' -e 'text returned of result' 2>/dev/null)"
if [ $? -ne 0 ]; then
    # The user pressed Cancel
    echo "User clicked Cancel"
    exit 1 # exit with an error status
elif [ -z "$newComputerName" ]; then
    # The user left the computer name blank
    echo "User left the computer name blank"
    /usr/bin/osascript -e 'Tell application "System Events" to display alert "No computer name entered; cancelling." as critical'
    exit 1 # exit with an error status
fi


### Set and log new computer name
/usr/sbin/scutil --set ComputerName "$newComputerName"
echo "New Computer Name: $newComputerName"

### Update the JSS
/usr/local/jamf/bin/jamf recon

# Inform user of computer renamed
jamfDisplayMessage "Renamed computer from: "$currentComputerName" to "$newComputerName""

echo "Renamed computer from: "$currentComputerName" to "$newComputerName""

exit 0      ## Success
exit 1      ## Failure

--
Dan

Tribruin
Valued Contributor
Valued Contributor

I wrote something similar as part of a larger deployment script. Here is the relevent portion. You will need to generate a CSV file and put it on the computer before running the script. CSV should be in the format:

New York, NY
United Kingdom, UK
Other, OT

But this should give you a starting point to work from:

#!/bin/bash

# This script will generate a computer name based on location, model type, and asset tag and update the computer name.

# Variables                                        

# Location of CSV file that includes Location Names, Location Abbreviation
BUILDNAMELIST="/path/to/BUILDINGS.csv"

# Determine the model type of the computer
MODELTYPE=$(sysctl hw.model | awk '{print $2}')

# Set these variables through a script or prompts. 
ASSETTAG='C123455'
LOC='New York'

GenerateComputerName() {                                                                    # Generate Computer Name based on Building, Mac Type (DT/LT), and Asset Tag
    #Get Location Prefix from text file
    PREFIX=$(cat $BUILDNAMELIST | grep "$LOC" | awk -F, '{print $2}')
    if [[ $PREFIX == "" || $LOC == "" ]]; then
        PREFIX="XXX"
    fi

    #Check to see if the Model Name is a "MacBook" or "Parallels" and assign model descriptor (LT, VM, or DT)
    COMPUTERNAME=$PREFIX
    if [[ ${MODELTYPE:0:7} == "MacBook" ]];                                                   # Check for "Macbook", if so, device is a Laptop
        then 
            COMPUTERNAME+="LT"
    elif [[ ${MODELTYPE:0:7} == "Paralle" ]];                                             # Check for "Parallels", if so, device is a Virtual Machine
        then
            COMPUTERNAME+="VM"            
    else 
            COMPUTERNAME+="DT"                                                                # Otherwise, the device must be a Desktop
    fi

    #Add Asset Tag Number to Name and "Mac" suffix
    COMPUTERNAME+=$ASSETTAG
    COMPUTERNAME+="Mac"
    echo $COMPUTERNAME
}

# Generate the computer name
NEWCOMPUTERNAME=$(GenerateComputerName)

# Update the Computer Name
/usr/sbin/scutil --set ComputerName $NEWCOMPUTERNAME
echo $NEWCOMPUTERNAME

mm2270
Legendary Contributor II

@MagicMick If you want to go the route of using the API to get the site name information, then you can try something like the following.
This script does some error checking, but not with everything. So if for example, the API name and password aren't correct or don't have the proper permissions, it will fail. Just something to keep in mind.

EDIT: Added a case statement for the Site name to set the site prefix characters. You'll need to add any extra checks as required.

#!/bin/bash

## The API username and password are obtained from script parameters 4 and 5
API_USER="$4"
API_PASS="$5"

JAMF_PLIST="/Library/Preferences/com.jamfsoftware.jamf.plist"

## Two sanity checks:
## 1. Make sure the Mac is enrolled in a JPS. The Jamf plist should be present for us to pull the URL from
## 2. Check to make sure we received parameters 4 and 5 for the API_USER and API_PASS variables or else we cannot get info using the API

if [ -e "$JAMF_PLIST" ]; then
    ## Here we get the URL for the Jamf Pro server this Mac is enrolled in
    echo "Found the Jamf plist. Checking for the URL now..."
    JPS_URL=$(/usr/bin/defaults read "$JAMF_PLIST" jss_url)
else
    echo "This Mac does not appear to be enrolled in a Jamf Pro server. Exiting..."
    exit 1
fi

if [[ -z "$API_USER" || -z "$API_PASS" ]]; then
    ## Either $4 or $5 weren't passed to the script, so we can't continue
    echo "The API user or API password items are blank. Please make sure the script parameters are correctly filled in and try again. Exiting..."
    exit 2
else
    echo "API variables were passed to the script. Continuing..."
fi

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

echo "UUID: $UUID"

## Here we get the Site name using the API
SITE_NAME=$(curl -H "Accept: application/xml" -sku "${API_USER}:${API_PASS}" "${JPS_URL}JSSResource/computers/udid/${UUID}/subset/general" | xpath '/computer/general/site/name/text()')

echo "Site Name: $SITE_NAME"

## Modify this case statement with additional checks to set the correct site tag for the final name
case "$SITE_NAME" in
    *"New York"*)
    SITE_PREFIX="NY" ;;
    *UK*)
    SITE_PREFIX="UK" ;;
    *Other*)
    SITE_PREFIX="OT" ;;
    *)
    SITE_PREFIX="$SITE_NAME" ;;
esac

## Get the Model ID from the device
MODEL_ID=$(sysctl hw.model | awk '{print $NF}')
echo "Model ID: $MODEL_ID"

## Determine the model prefix we should use based on the model id
case "$MODEL_ID" in
    iMac*)
    MODEL_PREFIX="iMac" ;;
    MacBook*)
    MODEL_PREFIX="MB" ;;
    MacPro*)
    MODEL_PREFIX="MP" ;;
    Macmini*)
    MODEL_PREFIX="MM" ;;
    *)
    MODEL_PREFIX="Mac" ;;
esac

echo "Model prefix: $MODEL_PREFIX"

promptForTag () {
### Ask user for the Asset Tag
ASSET_TAG=$(/usr/bin/osascript <<- EOF
tell application "System Events"
    get text returned of (display dialog "Enter the asset tag for this computer:" default answer "" buttons {"Enter"} default button 1)
end tell
EOF)
}

## This while loop will ensure we get an asset tag from the prompt
while [ -z "$ASSET_TAG" ]; do
    promptForTag
done

echo "Asset Tag: $ASSET_TAG"

## Assign the full new computer name to a variable
NEW_NAME="${SITE_PREFIX}${MODEL_PREFIX}${ASSET_TAG}"
echo "Computer will be renamed to: $NEW_NAME"

## Set the new computer name
/usr/sbin/scutil --set ComputerName "$NEW_NAME"

echo "Computer was renamed to: $NEW_NAME"

## Collect updated inventory
/usr/local/jamf/bin/jamf recon

Mauricio
Contributor II

In addition to mm2270 script above I would recommend adding:

A. For consistence, set the host names to the same as the computer.

    /usr/sbin/scutil --set LocalHostName "$NEW_NAME"
    /usr/sbin/scutil --set HostName "$NEW_NAME"

B. Check if the name has not been taken in Jamf. Rely on user's input can be challenging.

We have a process to autogenerate a unique computer name based on our naming convention and to test it we have this:

checkNameAvailable() {
    macName=""
    response=$(/usr/bin/curl -H "Accept: application/xml" -sku "${API_USER}:${API_PASS}" --write-out '%{http_code}' --output /dev/null --request GET "${JPS_URL}JSSResource/computers/name/$NEW_NAME" )

    case "$response" in
        200 ) echo "Computer Name $NEW_NAME in use" ;;
        404 ) macName="OK" ;;
        5** ) echo "Server error: $response" ;;
    esac

 }

generateComputerName() {
    genenerateName
    checkNameAvailable "$NEW_NAME"
    while true;
    do
      if [ -z "$macName" ]; then
        genenerateName
        checkNameAvailable "$NEW_NAME"
      else
        break
      fi
    done
    echo "$NEW_NAME"
}

Basically if you cannot find that computer name in Jamf means you are good to use it.

'genenerateName' function is the process to generate a new name...

@MagicMick You said "I am looking for a Self Service option where the user fills in some text (most likely an asset tag number)", do you have that in place already? Can you avoid that by just generating one automatically and saving the manual/self-service route?

MagicMick
Contributor

Hi @dan-snelson @RBlount @mm2270 @Mauricio

Thank you all so so much for your quick and detailed suggestion. I'm sure I'll be able to make good use of all the info provided. It really means a lot to me that you guys are willing to spend the time to help a fellow Admin.

@Mauricio If there was a way for me to know which tag belongs to which computer, I would have obviously done that. But with Zero Toch/DEP we send tags and machines seperately, the user needs to stick the tag ont he asset and then via a SS policy I want the user to let Jamf know which tag belongs to which machine. Does that make sense?

Mauricio
Contributor II

@MagicMick Indeed, it makes sense, if you have a naming process in place that uses tags, that is the way to do it. Regards.

MagicMick
Contributor

Hi @dan-snelson @RBlount @mm2270 @Mauricio

So I created a new script based on all your guys handy hints and tips. And it was working fine! But now under Big Sur it doesn't seem to work anymore? Any ideas?

#!/bin/sh

## Here we get the Site name using the API
SITE_NAME=$(curl -H "Accept: application/xml" -sku "${API_USER}:${API_PASS}" "${JPS_URL}JSSResource/computers/udid/${UUID}/subset/general" | xpath '/computer/general/site/name/text()')

echo "Site Name: $SITE_NAME"

## Modify this case statement with additional checks to set the correct site tag for the final name
case "$SITE_NAME" in
    *"New York"*)
    SITE_PREFIX="NY" ;;
    *Exeter*)
    SITE_PREFIX="EX" ;;
    *Orlando*)
    SITE_PREFIX="OL" ;;
    *)
    SITE_PREFIX="$SITE_NAME" ;;
esac

## Get the Model ID from the device
MODEL_ID=$(sysctl hw.model | awk '{print $NF}')
echo "Model ID: $MODEL_ID"

## Determine the model prefix we should use based on the model id
case "$MODEL_ID" in
    iMac*)
    MODEL_PREFIX="-IM-" ;;
    MacBook*)
    MODEL_PREFIX="-MB-" ;;
    MacPro*)
    MODEL_PREFIX="-MP-" ;;
    Macmini*)
    MODEL_PREFIX="-MM-" ;;
    *)
    MODEL_PREFIX="-Mc-" ;;
esac

echo "Model prefix: $MODEL_PREFIX"

promptForTag () {
### Ask user for the Asset Tag
ASSET_TAG=$(/usr/bin/osascript <<- EOF
tell application "System Events"
    get text returned of (display dialog "Enter the asset tag for this computer:" default answer "" buttons {"Enter"} default button 1)
end tell
EOF)
}

## This while loop will ensure we get an asset tag from the prompt
while [ -z "$ASSET_TAG" ]; do
    promptForTag
done

echo "Asset Tag: $ASSET_TAG"

## Assign the full new computer name to a variable
NEW_NAME="${SITE_PREFIX}${MODEL_PREFIX}${ASSET_TAG}"
echo "Computer will be renamed to: $NEW_NAME"

## Set the new computer name
/usr/sbin/scutil --set ComputerName "$NEW_NAME"
/usr/sbin/scutil --set LocalHostName "$NEW_NAME"
/usr/sbin/scutil --set HostName "$NEW_NAME"

echo "Computer was renamed to: $NEW_NAME"

## Collect updated inventory
/usr/local/jamf/bin/jamf recon

Script result: Found the Jamf plist. Checking for the URL now...
API variables were passed to the script. Continuing...
UUID: xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx
Usage:
/usr/bin/xpath5.28 [options] -e query [-e query...] [filename...]

If no filenames are given, supply XML on STDIN. You must provide at
least one query. Each supplementary query is done in order, the
previous query giving the context of the next one.

Options:

-q quiet, only output the resulting PATH.
-s suffix, use suffix instead of linefeed.
-p postfix, use prefix instead of nothing.
-n Don't use an external DTD.
Site Name: Model ID: iMac16,2
Model prefix: -IM-
Asset Tag: 00566
Computer will be renamed to: -IM-00566
scutil: invalid option -- I
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 -- I
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 -- I
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 was renamed to: -IM-00566
Retrieving inventory preferences from https://xxxxx.jamfcloud.com/...
Finding extension attributes...
Locating accounts...
Locating package receipts...
Locating applications...
Searching path: /System/Applications
Locating hard drive information...
Locating software updates...
Locating plugins...
Searching path: /Library/Internet Plug-Ins
Locating fonts...
Searching path: /private/var/jamfadmin/Library/Fonts
Searching path: /Users/XXXX/Library/Fonts
Searching path: /Library/Fonts
Searching path: /System/Library/Fonts
Searching path: /Applications
Searching path: /Library/Application Support/Adobe/Fonts
Locating hardware information (Mac OS X 10.16.0)...
Gathering application usage information...
Submitting data to https://XXXXX.jamfcloud.com/...
<computer_id>169</computer_id>

QuotedText

Mauricio
Contributor II

@MagicMick Big Sur, big surprises!

Apple got some changes for xpath, a good link:
https://scriptingosx.com/2020/10/dealing-with-xpath-changes-in-big-sur/

To fix your script I would recommend this:

Replace:

SITE_NAME=$(curl -H "Accept: application/xml" -sku "${API_USER}:${API_PASS}" "${JPS_URL}JSSResource/computers/udid/${UUID}/subset/general" | xpath '/computer/general/site/name/text()')

With:

SITE_NAME=$(curl -H "Accept: application/xml" -sku "${API_USER}:${API_PASS}" "${JPS_URL}JSSResource/computers/udid/${UUID}/subset/general" | xmllint --xpath '/computer/general/site/name/text()' -)

I hope this helps!

MagicMick
Contributor

@Mauricio Many many many thanks! All good now!