enrollment not working after testing unload/load of login window

laurendc
New Contributor

Greetings all - I'm working on adjusting our first run scripts and am experimenting with unloading and re-loading the login window in order to allow for time for first run scripts to run properly on our image. Things look good with adding this line at the beginning of the process:

/bin/launchctl unload /System/Library/LaunchDaemons/com.apple.loginwindow.plist

and then this line at the end:

/bin/launchctl load /System/Library/LaunchDaemons/com.apple.loginwindow.plist

However, the machine isn't enrolling. Our scripts without these lines work fine with enrollment so this is a bit odd. Should I perhaps add a sleep command to delay the unloading of the window or something? Perhaps unloading the window is messing with something else?

Casper 8.73
10.8.5

3 REPLIES 3

franton
Valued Contributor III

To be fair, this is the hard way of doing it. You have two different options to pursue.

1) Use iHook and a launch agent over the login window.
This is the method we use at UAL. You feed iHook a script and it's pretty customisable but only catch is it's not been updated in a while. Still works with 10.4 to 10.9. http://rsug.itd.umich.edu/software/ihook/

2) Use the VNC lock screen.
This is Oxford University's method. All credit here to @localhorst and his team on this one.

I've cut+pasted the relevant section from his JNUC 2012 slides.

#!/bin/sh
case ${OSTYPE} in
  darwin10*)     # Snow Leopard - Mac OS X 10.6
(open /System/Library/CoreServices/RemoteManagement/ ? AppleVNCServer.bundle/Contents/Support/LockScreen.app)&
    defaults write com.apple.dock autohide -bool true ; killall Dock
    ;;
  darwin12*)     # Mountain Lion - Mac OS X 10.8
/System/Library/CoreServices/RemoteManagement/ ? AppleVNCServer.bundle/Contents/Support/LockScreen.app/ ? Contents/MacOS/LockScreen &
;; esac
osascript -e 'tell app "Casper Imaging" to activate'

laurendc
New Contributor

@franton][/url][/url thanks - I am going to try the second option out (path of least resistance) and see how it goes. The first option actually sounds great since it appears to give techs more transparency. I get a lot of questions about the first run script process and I would love to show an interface that reflects it. So I may play with that as well. Am wondering if there's a way to get that to work with cocoaDialog, which I've started using here.

franton
Valued Contributor III

@laurendc Not a problem. What we do at UAL is comprised of three parts.

Part 1 - LaunchAgent for the loginwindow
You'll need this so iHook will run over the top. This is achieved with something like this. Note the script location:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.organisation.firstrunscript</string>
  <key>LimitLoadToSessionType</key>
  <array>
    <string>LoginWindow</string>
  </array>
  <key>Program</key>
<string>/firstrun/firstrun.sh</string>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

Part Two - LaunchAgent kicker script
This is needed because passing parameters via LaunchD is a major PITA. It's easier to write a wrapper such as this. Again, note the parameters being passed to iHook.app which stop it showing a titlebar on the window and specify the bash script to be run. The pain at this point is that the script will NOT run as the root user but with something more elevated than a standard user. It's some peculiarity of OS X i've found.

#!/bin/bash

# Script to load iHook and run the OS X firstrun script

# Author : r.purves@arts.ac.uk
# Version 1.0 : 1-11-2012

# iHook 1.2 - for status display over login window
# Copyright 2006 - Research Systems Unix Group
# http://rsug.itd.umich.edu/software/ihook

SCRIPT="/firstrun"

$SCRIPT/iHook.app/Contents/MacOS/iHook --no-titlebar --script=$SCRIPT/firstrun.hook

exit 0

Part Three - Firstrun Script

I'm not going to copy + paste my entire script in here, just some highlights to help you along but this is where you can sort things out nicely for your build.

#!/bin/bash

# Firstrun script for a freshly imaged JSS managed OS X client.

# Author      : r.purves@arts.ac.uk

# Set up the variables we need for future changes

RunLoc="/firstrun"
AdminPW="password"
MacModel=$( ioreg -l | awk '/product-name/ { split($0, line, """); printf("%s
", line[4]); }' )
PrefModel=$( defaults read /Library/Preferences/SystemConfiguration/preferences.plist Model )
errorcode=1
EnrollLD="/Library/LaunchDaemons/com.jamfsoftware.firstrun.enroll.plist"
EnrolWait=$(( 8 * 60 ))
EnrolWaitIncrement=30

# Start iHook progress display and to lock out the user from the mac

/bin/echo %BECOMEKEY
/bin/echo %WINDOWSIZE MAX
/bin/echo %WINDOWLEVEL HIGH
/bin/echo %WINDOWPOSITION CENTER
/bin/echo %BACKGROUND ./background.jpg
/bin/echo %BACKGROUNDSCALING PROPORTIONALLY
/bin/echo %BEGINPOLE
/bin/echo %SHOWTIMER
/bin/echo %0 Preparing to start OS X Software Deployment

# Set System Timezone to avoid clock sync issues and record imaging time.

systemsetup -settimezone Europe/London
systemsetup -setusingnetworktime on
systemsetup -setnetworktimeserver timeserver.address.here
/usr/sbin/ntpd -g -q

/bin/echo %TITLE "UAL Software Deployment - Started at" $( date )

# Hide users under UID 500 and create uadmin account here if it doesn't already exist

/bin/echo %6 Creating uadmin account

defaults write /Library/Preferences/com.apple.loginwindow.plist Hide500Users -bool YES

if id -u uadmin >/dev/null 2>&1; then
    echo "uadmin already exists. Skipping account creation."
else
    jamf createaccount -username uadmin -realname uadmin -password "$AdminPW" -home /Users/uadmin -shell /bin/bash -admin
fi

# Disable iCloud popup.

/bin/echo %12 Disabling iCloud pop up on first login
mv -f -v /System/Library/CoreServices/Setup Assistant.app/Contents/SharedSupport/MiniLauncher /System/Library/CoreServices/Setup Assistant.app/Contents/SharedSupport/MiniLauncher.backup

# Make sure the computer has enrolled

/bin/echo %24 Enrolling computer in JSS

echo "Checking to see if JAMF enroll.sh is still running"

while [ -e "$EnrollLD" ]; do
    if [ $EnrolWait -le 0 ]; then
        echo "Reached wait timeout of ${EnrolWait} seconds!" >> $LOGFILE
        break
    fi

    echo "Still not complete. Waiting another ${EnrolWaitIncrement} seconds..." >> $LOGFILE
    sleep $EnrolWaitIncrement 
    (( EnrolWait -= $EnrolWaitIncrement ))
done    

jamf enroll -verbose

# Set up error trapping function for multiple jamf binary processes

function multiplejamf {
    # Check to see if jamf binary is running, and wait for it to finish.
    # Trying to avoid multiple triggers running at once at the expense of time taken.
    # There are two existing jamf processes running at all times. More than that is bad for us!

    TEST=$( pgrep jamf | wc -l )

    while [ $TEST -gt 2 ]
    do
        /bin/echo Waiting for existing jamf processes to finish ...
        sleep 3
        TEST=$( pgrep jamf | wc -l )
    done
}

# Set energy saving settings to never sleep

/bin/echo %30 Setting Energy Saving Settings for Deployment

/usr/bin/pmset -a displaysleep 0
/usr/bin/pmset -a disksleep 0
/usr/bin/pmset -a sleep 0

# Fix the incorrect model name in /Library/Preferences/SystemConfiguration/preferences.plist
# Also make sure the .plist is in the correct format

/bin/echo %36 Setting correct network details

if [[ "$PrefModel" != "$MacModel" ]];
then
  /bin/echo $AdminPW | sudo -S defaults write /Library/Preferences/SystemConfiguration/preferences.plist Model $MacModel
  /bin/echo $AdminPW | sudo -S plutil -convert xml1 /Library/Preferences/SystemConfiguration/preferences.plist
fi

# Fix the incorrect network service names
# Script lovingly stolen from https://jamfnation.jamfsoftware.com/discussion.html?id=3422

# Detect new network hardware
networksetup -detectnewhardware

# List all network services and read one by one
networksetup -listallnetworkservices | tail -n +2 | while read service
do

# Remove asterisk from string for renaming disabled services
    service=${service#**}

# Use filter to select next line which has the hardware port defined
    filter=false

# Display network services
    networksetup -listnetworkserviceorder | while read serviceorder
    do
        if [[ ${filter} == true ]]
        then
            # Grab hardware port
            hardwareport=`echo ${serviceorder} | sed -e 's/(Hardware Port: //;s/, Device:.*//'`

            # Check if service name if different
            if [[ ${service} != ${hardwareport} ]]
            then
                # Rename the network service
                networksetup -renamenetworkservice "${service}" "${hardwareport}"
                echo -e "Renamed network service "${service}" to "${hardwareport}""
            fi
        fi

        if [[ ${serviceorder} == *${service} ]]
        then        
            # Got the line with the service. Set the filter to true to grab the next line which contains the hardware port
            filter=true
            else
            filter=false
        fi
    done
done

# JAMF imaging should have set the machine name correctly. Let's make sure hostname is also set properly

setName=`networksetup -getcomputername`
scutil --set ComputerName ${setName}
scutil --set LocalHostName ${setName}
scutil --set HostName ${setName}

# Enable Assistive Device Access

/bin/echo %42 Enable Assistive Device Access

/usr/bin/touch /private/var/db/.AccessibilityAPIEnabled

# Install scoped software
# We execute the multiplejamf function before each policy call to make sure triggers don't conflict.

/bin/echo %60 Installing Initial Software

multiplejamf    
    jamf policy -trigger SoftwareInstall -verbose
multiplejamf
    jamf recon

/bin/echo %66 Installing Updates

multiplejamf
    jamf policy -trigger UpdatePolicy -verbose
multiplejamf
    jamf recon

/bin/echo %72 Installing MCX Settings

multiplejamf
jamf mcx

# Final recon to make sure Inventory is up to date.

/bin/echo %78 Updating computer inventory record
multiplejamf
    jamf recon

# Cleanup on aisle three!

/bin/echo %88 Final cleanup of files

rm -f /Library/LaunchAgents/com.firstrun.plist
rm -rf /firstrun

# Shutdown iHook and the computer

/bin/echo %100 Complete! Mac will now restart in 10 seconds
/bin/sleep 10
/bin/echo echo %ENDPOLE

/bin/echo $AdminPW | sudo -S /sbin/shutdown -r now

exit 0

For the record, this is 1) a very simplified version of what we run and 2) I'm still unhappy with the cludgework to run certain commands as root. Saying that, it's worked ok for us for some time at the expense that I have to rebuild our first run package every time we have a password change.