Workflow for DEP enrollment with Macs

chris_morelock
New Contributor II

I apologize if this has been asked already, but I am new to JAMF and wanted to see what you guys were doing.

I would like my macs to enroll via DEP, get prompted for the user to enter the computer name, then bind to AD. The problem is I cannot figure out how to rename BEFORE it binds to AD. How are ya'll doing it? Also, if you can share your script to prompt the user to rename their computer that would be great!

Thanks guys!

2 ACCEPTED SOLUTIONS

mbezzo
Contributor III

Hi Chris,
What we do is trigger a policy from "enrollment complete" that runs a script that checks the current UID and loops until it's a 501 (or 502 in our specific case) and THEN move on to a loop that waits for the dock to load. At that point we start the naming/binding/everything else.

Here's some snippets of the scripts we use:

"Waiting for user to finish logging in" Script:

#!/bin/bash

# Function to add date to log entries
log(){
NOW="$(date +"*%Y-%m-%d %H:%M:%S")"
echo "$NOW": "$1"
}

# Logging for troubleshooting - view the log at /var/log/prefirstrun.log
touch /var/log/prefirstrun.log
exec 2>&1>/var/log/prefirstrun.log

# Disable Software Updates during imaging
softwareupdate --schedule off
log "Software Updates disabled"

# Get the currently logged in user
loggedInUser=`python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");'`
log "Current user is $loggedInUser"

# get UID for current User
currentUID=$(dscl . -list /Users UniqueID | grep $loggedInUser | awk '{print $2;}')
log "$loggedInUser UID is $currentUID"

# Check and see if we're currently running as the user we want to setup - pause and wait if not
while [ $currentUID -ne 502 ] && [ $currentUID -ne 501 ]; do
    log "Currently logged in user is NOT the 501 or 502 user. Waiting."
    sleep 5
    loggedInUser=`python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");'`
    currentUID=$(dscl . -list /Users UniqueID | grep $loggedInUser | awk '{print $2;}')
    log "Current user is $loggedInUser with UID $currentUID"
done

# Now that we have the correct user logged in - need to wait for the login to complete so we don't start too early
dockStatus=$(pgrep -x Dock)
log "Waiting for Desktop"
while [ "$dockStatus" == "" ]; do
  log "Desktop is not loaded. Waiting."
  sleep 5
  dockStatus=$(pgrep -x Dock)
done

# Start the imaging process since we're now running as the correct user.
log "501 or 502 user is now logged in, continuing setup."
jamf policy -event firstRun

exit 0

Prompt for naming script:

#!/bin/sh

# Prompt user to name computer
computerNamePrompt(){
    # $1 = window title
    # $2 = prompt text
    # $3 = default answer
    su - "${loggedInUser}" -c osascript <<EOT
        tell application "System Events"
            with timeout of 8947848 seconds
                text returned of (display dialog "$2" default answer "$3" buttons {"OK"} default button 1 with title "$1" with icon ("path/to/icon.icns" as POSIX file))
            end timeout
        end tell
EOT
}

# Ask for Computer name to use when binding
log "Prompting user to enter computer name"
computerName="$(computerNamePrompt 'Enter Computer Name' 'Please enter a Computer Name following the companyname standard.

Example: computernamestandard' 'genericizedcomputername')"
log "User entered $computerName"

Hopefully this will get ya started. This took a lot of playing around with to get a good solution! It seems Apple has changed things fairly recently and now DEP isn't triggering as early as it used to - we would have so many policies run as "_mbsetupuser" which just didn't work for us. The looping scripts did the trick and allow the Jamf policies to start at a more reasonable time.

Good luck!
Matt

View solution in original post

stevevalle
Contributor III

Our staff Macs bind to AD using the serial number of the computer. When the user logs in for the first time, they are prompted to insert the Asset ID of the Mac. This Asset ID is also used as the computer name.

The script we use to prompt and rename:

#!/bin/sh

# Loop until valid input is entered or Cancel is pressed.
while :; do
    computerName=$(osascript -e 'Tell application "System Events" to display dialog "Please insert your Asset ID number and click Submit:" default answer "" buttons {"Submit"} with icon caution' -e 'text returned of result' 2>/dev/null)

    if (( $? ));
        then exit 1; fi  # Abort, if user pressed Cancel.

        computerName=$(echo -n "$computerName" | sed 's/^ *//' | sed 's/ *$//')  # Trim leading and trailing whitespace.

    if [[ -z "$computerName" ]]; then

        # The user left the Asset ID number blank
        osascript -e 'Tell application "System Events" to display alert "You must enter your Asset ID number. Please try again" as warning' >/dev/null

        # Continue loop to prompt again.

        else
            # Valid input: exit loop and continue.
            break
    fi
done

/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..."
echo "<result>`scutil --get ComputerName`</result>"

exit 0

View solution in original post

9 REPLIES 9

jwojda
Valued Contributor II

To my knowledge there isn't. My work around is to let it bind and do it's thing, then once the machine is done and the user logs in, run a self service policy to unbind, prompt for the machine name, then rebind (among other things, browser runs, first boot scripts, etc).

mbezzo
Contributor III

Hi Chris,
What we do is trigger a policy from "enrollment complete" that runs a script that checks the current UID and loops until it's a 501 (or 502 in our specific case) and THEN move on to a loop that waits for the dock to load. At that point we start the naming/binding/everything else.

Here's some snippets of the scripts we use:

"Waiting for user to finish logging in" Script:

#!/bin/bash

# Function to add date to log entries
log(){
NOW="$(date +"*%Y-%m-%d %H:%M:%S")"
echo "$NOW": "$1"
}

# Logging for troubleshooting - view the log at /var/log/prefirstrun.log
touch /var/log/prefirstrun.log
exec 2>&1>/var/log/prefirstrun.log

# Disable Software Updates during imaging
softwareupdate --schedule off
log "Software Updates disabled"

# Get the currently logged in user
loggedInUser=`python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");'`
log "Current user is $loggedInUser"

# get UID for current User
currentUID=$(dscl . -list /Users UniqueID | grep $loggedInUser | awk '{print $2;}')
log "$loggedInUser UID is $currentUID"

# Check and see if we're currently running as the user we want to setup - pause and wait if not
while [ $currentUID -ne 502 ] && [ $currentUID -ne 501 ]; do
    log "Currently logged in user is NOT the 501 or 502 user. Waiting."
    sleep 5
    loggedInUser=`python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");'`
    currentUID=$(dscl . -list /Users UniqueID | grep $loggedInUser | awk '{print $2;}')
    log "Current user is $loggedInUser with UID $currentUID"
done

# Now that we have the correct user logged in - need to wait for the login to complete so we don't start too early
dockStatus=$(pgrep -x Dock)
log "Waiting for Desktop"
while [ "$dockStatus" == "" ]; do
  log "Desktop is not loaded. Waiting."
  sleep 5
  dockStatus=$(pgrep -x Dock)
done

# Start the imaging process since we're now running as the correct user.
log "501 or 502 user is now logged in, continuing setup."
jamf policy -event firstRun

exit 0

Prompt for naming script:

#!/bin/sh

# Prompt user to name computer
computerNamePrompt(){
    # $1 = window title
    # $2 = prompt text
    # $3 = default answer
    su - "${loggedInUser}" -c osascript <<EOT
        tell application "System Events"
            with timeout of 8947848 seconds
                text returned of (display dialog "$2" default answer "$3" buttons {"OK"} default button 1 with title "$1" with icon ("path/to/icon.icns" as POSIX file))
            end timeout
        end tell
EOT
}

# Ask for Computer name to use when binding
log "Prompting user to enter computer name"
computerName="$(computerNamePrompt 'Enter Computer Name' 'Please enter a Computer Name following the companyname standard.

Example: computernamestandard' 'genericizedcomputername')"
log "User entered $computerName"

Hopefully this will get ya started. This took a lot of playing around with to get a good solution! It seems Apple has changed things fairly recently and now DEP isn't triggering as early as it used to - we would have so many policies run as "_mbsetupuser" which just didn't work for us. The looping scripts did the trick and allow the Jamf policies to start at a more reasonable time.

Good luck!
Matt

chris_morelock
New Contributor II

Thank you guys for the info! I will try it out

sjmosher
New Contributor II

One thing that we found helpful in our new machine workflow: it was discovered that if binding to AD through JAMF via policy object, the policy will take the name of the computer as it was at the start of the policy/script/etc when triggered
. In our instance, we have to rename the system, then reboot and then bind. When trying to bind as part of the same sequence of tasks, AD would get a blank name. Post reboot, the name binds successfully. Hope this helps!

kquan
Contributor

@mbezzo _mbsetup user triggering policies even without the "enrollment complete" trigger has been problematic for us here at my company, specifically happening with machines shipped with 10.12.4 and up.

I did make a post on JAMF Nation here :
https://www.jamf.com/jamf-nation/discussions/24237/dep-w-10-12-5-done-from-internet-recovery-account-creation-issue

Be curious if you'd have any suggestions to this!

Much appreciated!

stevevalle
Contributor III

Our staff Macs bind to AD using the serial number of the computer. When the user logs in for the first time, they are prompted to insert the Asset ID of the Mac. This Asset ID is also used as the computer name.

The script we use to prompt and rename:

#!/bin/sh

# Loop until valid input is entered or Cancel is pressed.
while :; do
    computerName=$(osascript -e 'Tell application "System Events" to display dialog "Please insert your Asset ID number and click Submit:" default answer "" buttons {"Submit"} with icon caution' -e 'text returned of result' 2>/dev/null)

    if (( $? ));
        then exit 1; fi  # Abort, if user pressed Cancel.

        computerName=$(echo -n "$computerName" | sed 's/^ *//' | sed 's/ *$//')  # Trim leading and trailing whitespace.

    if [[ -z "$computerName" ]]; then

        # The user left the Asset ID number blank
        osascript -e 'Tell application "System Events" to display alert "You must enter your Asset ID number. Please try again" as warning' >/dev/null

        # Continue loop to prompt again.

        else
            # Valid input: exit loop and continue.
            break
    fi
done

/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..."
echo "<result>`scutil --get ComputerName`</result>"

exit 0

chris_morelock
New Contributor II

Thank you guys!

RobertPetrie
New Contributor II

I am experimenting with this script to rename the Macs with the serial number:

!/usr/bin/env bash

Get the Serial Number of the Machine

sn=$(system_profiler SPHardwareDataType | awk '/Serial/ {print $4}')

Set the ComputerName, HostName and LocalHostName

scutil --set ComputerName mac$sn
scutil --set HostName mac$sn
scutil --set LocalHostName mac$sn

When it runs, it does change the name of the Mac to something like "mac1Q2W3E4R5T" but when the Mac is then joined to the domain after this with a policy, it joins the domain with the name "No Name".

Is anyone else seeing this or have a way round it?

sjmosher
New Contributor II

@RobertPetrie Yes, we've run into that issue. The problem is that when running a workflow in order, the AD binding will use whatever the name of the system was at the beginning of that chain. In our case, we had the following:

[ Set to the 'deploy' trigger ]
100 - rename computer
200 - add local admin
300 - bind to AD
400 - etc.

The 300 - bind to AD policy used the system name as it existed when the 'deploy' trigger was run, before step 100. This caused the system to bind with a bad name.

To circumvent the issue, we did a reboot and had a different trigger run the AD bindings. Reboot isn't necessary, but was helpful for our workflow. See an example below:

[ Set to the 'deploy' trigger ]
100 - rename computer
200 - add local admin + run script triggering 'deploy2'
[ Set to the 'deploy2' trigger ]
300 - bind to AD
400 - etc.

Hope this helps!