Posted on 05-24-2013 01:13 PM
Hello,
We are looking at the process for upgrading our Lion MacBook Airs to Mountain Lion and have run into a situation where an application needs to get installed right after the Mountain Lion upgrade for logins to work properly. Is there a way to queue a package install for "first boot" like you can for imaging?
Tim
Posted on 05-24-2013 01:42 PM
We just had all of our teachers update their laptops to 10.8.3 through Self Service and we used a LaunchDaemon to trigger a "Cleanup" policy that ran at first boot after the update ran.
We used the post imaging style window to cover the login window while this was running, and the policy did things like:
When it was done it ran Recon and rebooted. It worked great for us. The entire process generally took about an hour from start to finish. I'd be happy to send more information if it would be helpful.
Posted on 05-24-2013 01:45 PM
Is the product able to be installed without someone logged into the Mac? I'm assuming yes or you would have a bit of a chicken and egg problem on your hands. :)
If so, you could scope a policy with a trigger of "startup" to Macs in the process of being upgraded. You'd need a reliable way to identify any Macs that have begun the upgrade process, but aren't actually upgraded yet. Perhaps a dummy receipt or something to that affect dropped on the Macs when they initiate the upgrade process and a recon to pull them into a Smart Group.
There may be more efficient ways to do it, but hopefully that gives you an idea or two. A custom one time LaunchDaemon might also work, but it might be overkill for this situation.
Posted on 05-24-2013 02:19 PM
I tested doing it in the way that mm2270 described but ran into quite a few cases where it didn't work properly, which is why I switched to using a LaunchDaemon. This jives with what I heard from a few others as well; Smart Groups and startup policies weren't as reliable as we'd all hoped. We just moved 2,000 laptops with our process using the LaunchDaemon and our failure rate was super small.
Posted on 05-28-2013 01:32 AM
I have been testing with a 10.8 upgrade using Greg Neagle's brilliant Son of InstallLion package and was trying to use manual triggers in the self service policy to recreate <500 accounts, User Template plists which get hosed in the upgrade via scripts but its not working for me.
I have read launchd is the way to go but I'm a novice when it comes to creation and implementation within the 10.8 upgrade package in the policy.
Any advice would be appreciated.
Cheers
Tim
Posted on 05-28-2013 03:15 AM
I've developed a installer package-based solution for this issue, where you can install packages at first boot following a createOSXinstallPkg-driven upgrade. I've posted about it here:
http://derflounder.wordpress.com/2013/05/13/first-boot-package-install-pkg/
The installer package is available here on my GitHub repo:
Posted on 05-28-2013 06:29 AM
I am going to take a look at that createOSXinstall.pkg option, but, Andrew, I would be interested in reading more about your LaunchDaemon solution as well. It might fit in quicker to our current install than starting completely over with the createOSXinstall.pkg.
Tim
Posted on 05-28-2013 08:16 AM
This might seem like overkill, but with 2,000 people running it, I wanted it to be pretty fool proof. Less than 10% of the machines that ran it had problems, and the problems were due to things like network issues or staff people not plugging into power, etc; not problems with the process itself. It allowed users to just plugin, start the install from Self Service and come back about an hour later to an updated and patched machine that still had all of their data/apps. We were very happy with how it went.
Here's what we did...
##############################################################
Created a Smart Group of computers that were eligible for the 10.8 update. Criteria for this group was "like 10.7" or "is 10.6.8", and "not like 10.8", and then all of the hardware specific requirements for 10.8 (proc, memory, excluded models, etc).
Created a policy scoped to this group, called "Install Mountain Lion", in Self Service. This policy installs these items:
##############################################################
The "Mountain Lion Cleanup Trigger" package includes a LaunchDaemon (set to Run at Load) and the script it runs. The script looks like this:
#!/bin/sh
# Triggers policy that runs post Mountain Lion installation items
# AS (1-22-13)
echo "Pausing 30 seconds..."
/bin/sleep 30
# variables
OSVERSION=`/usr/bin/sw_vers | /usr/bin/grep ProductVersion | /usr/bin/awk '{print $2}' | sed -Ee 's/^[0-9]+.([0-9]+).[0-9]+$/1/'`
if [ "$OSVERSION" = 8 ]; then
# Create file that Extenstion Attribute is based off of
/usr/bin/touch /Library/Management/.mountainlion
# Remove items to catch failures
if [ -f /Library/LaunchAgents/us.or.k12.beaverton.ml_error_cleanup.plist ]; then
/bin/rm -f /Library/LaunchAgents/us.or.k12.beaverton.ml_error_cleanup.plist
else
/bin/rm -f /Library/Management/us.or.k12.beaverton.ml_error_cleanup.plist
fi
/bin/rm -f /Library/Management/ml_error_cleanup.sh
/bin/rm -f /Library/Management/OS-X-Mountain-Lion.png
echo "Running Mountain Lion Cleanup Policy"
/usr/sbin/jamf policy -action MountainLionCleanup
else
/bin/echo "Not Running 10.8. Will abort Post Mountain Lion Cleanup."
# Move Failure Launch Agent into place so user gets popup
/bin/mv /Library/Management/us.or.k12.beaverton.ml_error_cleanup.plist /Library/LaunchAgents/
/usr/sbin/chown root:admin /Library/LaunchAgents/us.or.k12.beaverton.ml_error_cleanup.plist
/bin/chmod 644 /Library/LaunchAgents/us.or.k12.beaverton.ml_error_cleanup.plist
# Create file that Extenstion Attribute is based off of
/usr/bin/touch /Library/Management/.mountainlion_fail
# Stop the loginwindow image from showing
/usr/bin/killall -m jamfHelper
# Remove Launch items meant for post install cleanup
/bin/mv /Library/LaunchDaemons/com.bsd.MountainLionCleanup.plist /Library/Management/
/usr/sbin/chown root:wheel /Library/Management/com.bsd.MountainLionCleanup.plist
/bin/rm /Library/LaunchAgents/com.bsd.postimage.2012.plist
# Refresh the login window for good measure
/usr/bin/killall loginwindow
# Run Recon so machine gets into group of failed 10.8 machines via extension attribute
/usr/sbin/jamf recon
fi
As you can see, the script checks the OS and if it's 10.8 (which means the installer ran successfully), it creates a file for an extension attribute so we know it ran the update successfully, and then triggers a policy that runs all of the cleanup items. If the OS is not 10.8, we know the update failed, so it kills and removes the JAMFHelper login window pop up and moves the Launch D item so that it doesn't run at reboot every time. It also moves the "failure" Launch Agent into place so that users are notified at login that the install failed. I put this in place because there were some machines that the 10.8 update wouldn't run successfully on, and this would give the user a way of knowing that it hadn't actually worked. Might not be necessary if you're only doing a few machines, but for 2,000 I wanted to have our bases covered.
##############################################################
The "Mountain Lion Didn't Install Cleanup" package includes a Launch Agent that calls this script:
#!/bin/bash
####################################################################################################
# Meant to run if 10.8 Self Service Install fails
# Prompts User to Update to 10.8
# AS
####################################################################################################
####################################################################################################
if [ -d /Library/Application Support/JAMF/bin/jamfHelper.app ]; then
userDecision=`/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "Company Name Here" -heading "10.8 Update Failed!" -alignHeading center -description 'This computer appears to have failed the 10.8 Mountain Lion Update. Please click on "Install Now" to open Self Service so that you can start the update again.' -button2 "Install Now" -defaultButton 2 -icon "/Library/Management/OS-X-Mountain-Lion.png" -iconSize 125 &`
else
echo "Could not find jamfHelper.app"
exit 0
fi
if [ "$userDecision" = 2 ]; then
echo "Opening Self Service"
# Open Self Service
open /Applications/Self Service.app
else
echo User cancelled
fi
##############################################################
The "Mountain Lion Cleanup" policy that gets triggered after the update successfully ran, runs the following items:
##############################################################
"mountain_lion_cleanup_after" script contents:
#!/bin/bash
##################################################################################################################################
# Runs cleanup items at end of Mountain Lion Install Cleanup policy
# This is a combination of other scripts
# AS
##################################################################################################################################
##################################################################################################################################
###################################################################################################################################
# Turn off Java Updates and remove Launch Agent pop up
##################################################################################################################################
####################################################################################################
####################################################################################################
/bin/echo "Beginning running disable_java_updates script"
####################################################################################################
# Get number variable needed to set suppression of update reminder
####################################################################################################
NUMBER=`/bin/cat /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Enabled.plist |grep ';deploy=' |cut -d"=" -f2 |cut -d"<" -f1`
echo The number for suppression of this version of Java is "$NUMBER"
# Verify that it received a numeric value
case "$NUMBER" in
[0-9]*)
echo "Entry is a numeric value. Continuing..."
;;
* )
echo "Error: This entry is not a number. Will fail to properly suppress update pop up."
;;
esac
####################################################################################################
# Remove Updater Launch Agent Sym Link that gets created during updates
####################################################################################################
/bin/echo "Checking to see if Launch Agent sym link exists..."
if [ -f /Library/LaunchAgents/com.oracle.java.Java-Updater.plist ]; then
/bin/echo "Launch Agent exists. Unloading and removing."
/bin/rm /Library/LaunchAgents/com.oracle.java.Java-Updater.plist
/bin/echo "Removed Update Launch Agent Sym Link"
else
/bin/echo "Launch Agent does not exist."
fi
####################################################################################################
# Remove Updater Launch Daemon Sym Link that gets created during updates
####################################################################################################
/bin/echo "Checking to see if Launch Daemon sym link exists..."
if [ -f /Library/LaunchDaemons/com.oracle.java.Helper-Tool.plist ]; then
/bin/echo "Launch Daemon exists. Unloading and removing."
/bin/rm /Library/LaunchDaemons/com.oracle.java.Helper-Tool.plist
/bin/echo "Removed Update Launch Daemon Sym Link"
else
/bin/echo "Launch Daemon does not exist."
fi
####################################################################################################
####################################################################################################
# Check to see if Java Plugin exists
if [ -d /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home ]; then
echo "Java Plugin is installed, continuing..."
if [ ! -f /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties ]; then
/bin/echo "The deployment.properties file does not yet exist. Will create..."
# Create deployment.properties file
/usr/bin/touch /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo "Created deployment.properties file"
# Change ownership on this new file
/usr/sbin/chown root:wheel /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo "Changed ownership on deployment.properties file"
# Change permissions on this file
/bin/chmod 755 /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo "Changed permissions on deployment.properties file"
# Write contents of this file
/bin/echo '#deployment.properties' > /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo deployment.macosx.check.update.locked >> /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo deployment.macosx.check.update=false >> /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo deployment.expiration.decision.suppression."$NUMBER".locked >> /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo deployment.expiration.decision.suppression."$NUMBER"=true >> /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo deployment.expiration.decision."$NUMBER".locked >> /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo deployment.expiration.decision."$NUMBER"=later >> /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo "Wrote content to deployment.properties file. Have a wonderful day."
else
/bin/echo "deployment.properties file already exists. Removing and building new version..."
# Delete existing version of the file
/bin/rm -f /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo "Deleted previous deployment.properties file"
# Create deployment.properties file
/usr/bin/touch /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo "Created deployment.properties file"
# Change ownership on this new file
/usr/sbin/chown root:wheel /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo "Changed ownership on deployment.properties file"
# Change permissions on this file
/bin/chmod 755 /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo "Changed permissions on deployment.properties file"
# Write contents of this file
/bin/echo '#deployment.properties' > /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo deployment.macosx.check.update.locked >> /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo deployment.macosx.check.update=false >> /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo deployment.expiration.decision.suppression."$NUMBER".locked >> /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo deployment.expiration.decision.suppression."$NUMBER"=true >> /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo deployment.expiration.decision."$NUMBER".locked >> /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo deployment.expiration.decision."$NUMBER"=later >> /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/deployment.properties
/bin/echo "Wrote content to deployment.properties file. Have a wonderful day."
fi
else
echo "Error: Failure to find Java Plugin path. Either Java is not installed, or the path within the plugin has changed. Exiting"
fi
/bin/echo "Finished running disable_java_updates script"
##################################################################################################################################
########################################
# Disables iCloud/Apple ID Login Pop up
########################################
# Remove existing Setup Assistant file from all existing user directories
/bin/rm -rf /Users/*/Library/Preferences/com.apple.SetupAssistant.plist
/bin/rm -rf /Users/*/Library/Preferences/com.apple.loginwindow.plist
/bin/rm -rf /Users/*/Library/Preferences/loginwindow.plist
# Remove our local admin Setup and Login Window files
/bin/rm -rf /private/var/ouradmin/Library/Preferences/com.apple.SetupAssistant.plist
/bin/rm -rf /private/var/ouradmin/Library/Preferences/com.apple.loginwindow.plist
/bin/rm -rf /private/var/ouradmin/Library/Preferences/loginwindow.plist
echo "Removed Setup Assistant file and Login Window files for all users"
# Copy items to any existing user folders except Shared
find /Users -maxdepth 1 -type d ! -name Shared -mindepth 1 -exec /bin/cp -r /System/Library/User Template/English.lproj/Library/Preferences/com.apple.SetupAssistant.plist {}/Library/Preferences/com.apple.SetupAssistant.plist ;
find /Users -maxdepth 1 -type d ! -name Shared -mindepth 1 -exec /bin/cp -r /System/Library/User Template/English.lproj/Library/Preferences/loginwindow.plist {}/Library/Preferences/loginwindow.plist ;
find /Users -maxdepth 1 -type d ! -name Shared -mindepth 1 -exec /bin/cp -r /System/Library/User Template/English.lproj/Library/Preferences/com.apple.loginwindow.plist {}/Library/Preferences/com.apple.loginwindow.plist ;
# Copy items to our local admin folder
/bin/cp -r /System/Library/User Template/English.lproj/Library/Preferences/com.apple.SetupAssistant.plist private/var/ouradmin/Library/Preferences/com.apple.SetupAssistant.plist
/bin/cp -r /System/Library/User Template/English.lproj/Library/Preferences/com.apple.loginwindow.plist private/var/ouradmin/Library/Preferences/com.apple.loginwindow.plist
/bin/cp -r /System/Library/User Template/English.lproj/Library/Preferences/loginwindow.plist private/var/ouradmin/Library/Preferences/loginwindow.plist
echo "Copied Setup Assistant file and Login Window files for all users"
# Change ownership on this folder to the user
for user in `find /Users -maxdepth 1 -type d ! -name Shared -mindepth 1 |cut -d/ -f3`
do
/usr/sbin/chown -R $user /Users/$user/Library/Preferences/
done
# Change our local admin file ownership
/usr/sbin/chown -R ouradmin /private/var/ouradmin/Library/Preferences/com.apple.SetupAssistant.plist
/usr/sbin/chown -R ouradmin /private/var/ouradmin/Library/Preferences/com.apple.loginwindow.plist
/usr/sbin/chown -R ouradmin /private/var/ouradmin/Library/Preferences/loginwindow.plist
echo "Changed owernship on Setup Assistant file for all users"
##################################################################################################################################
####################################################################################
# Finishes cleanup, removes Launch Items, updates Login window, runs Recon, Reboots
####################################################################################
# Create File that Extension attribute is built off of
/usr/bin/touch /Library/Management/.mountainlion
echo "Created Mountain Lion file for Extension Attribute"
# If Failure file exists, remove
if [ -f /Library/Management/.mountainlion_fail ]; then
/bin/rm -f /Library/Management/.mountainlion_fail
echo "Removed failed Mountain Lion file that existed. Machine must have previously failed install. This will now show up as a failed machine in policy log."
fi
# Trigger Policy that will change Apple logo at Login Window to our Logo
/usr/sbin/jamf policy -action InstallBSDLogoLion
echo "Ran Logo policy"
# Remove Launch Item that triggered this policy
/bin/rm /Library/LaunchDaemons/com.bsd.MountainLionCleanup.plist
echo "Removed Mountain Lion Cleanup startup item"
# Run Recon
echo "Running Recon..."
/usr/sbin/jamf recon
#Remove the plist file so that it doesn't pop up again
/bin/rm /Library/LaunchAgents/com.bsd.postimage.2012.plist
echo "Removed Launch Item that triggered Login Window Message"
# Stop the loginwindow image from showing
/usr/bin/killall -m jamfHelper
echo "Killed jamfHelper Login Window item"
# Refresh the login window for good measure
/usr/bin/killall loginwindow
echo "Refreshed the Login Window"
# Reboot in one minute
echo "This is the last cleanup line. Will reboot in one minute..."
/sbin/shutdown -r +1
##################################################################################################################################
##################################################################################################################################
##################################################################################################################################
##############################################################
Hope this helps...