Skip to main content
Jamf Nation, hosted by Jamf, is a knowledgeable community of Apple-focused admins and Jamf users. Join us in person at the ninth annual Jamf Nation User Conference (JNUC) this November for three days of learning, laughter and IT love.

Guide to setting up a package for in-place macOS upgrade?

Is there a guide somewhere with a full set of instructions from start to finish for what I would need to do in order to set up a package to allow me to do an unattended in-place macOS upgrade using Casper Remote?

Specifically from OS X 10.10 to OS X 10.11 (a sizable chunk of our equipment cannot go to 10.12 so we don't want to move to that yet).

I'm looking to do this during the summer break but I want to set things up and test it beforehand so I can check a) that it works and b) how much time it takes.

Thanks,
Dan Jackson (Lead ITServices Technician)
Long Road Sixth Form College
Cambridge, UK.

Like Comment
Order by:
SOLVED Posted: by roiegat

This guide is good:
https://derflounder.wordpress.com/category/createosxinstallpkg/

We do it a bit differently though. I have a script that runs first to check hard drive space and that they are eligible for the update. Once that's done it runs a policy that caches the installer on the machine, then another policy runs to run the cached installer.

Because we use policies and scripts, we can add a self service start as well if we want to give people an option to do it on their own time.

The nice thing is that this process is pretty much the same no matter was OS your upgrading to (assuming is a Mac one). So once you learn to do it once and have it working in your environment, not that hard to change it for the next OS.

Like
SOLVED Posted: by tak10

I've used this document to release OS upgrade.
https://resources.jamf.com/documents/technical-papers/Deploying-OS-X-v10.7-or-Later-with-the-Casper-Suite.pdf

Since you are running this unattended, instead of putting the policy as self service item, you can probably do the recurring check-in trigger to run the update.

We keep it as self service and since we don't have the summer break to run the upgrades so we have to communicate to the user to run the upgrade when they have time to do so.

Like
SOLVED Posted: by sepiemoini

I've used the Jamf approach mentioned by @tak10 in the past but have since adopted @Rosko's workflow (with some slight modifications). @Rosko's approach can be found here.

Like
SOLVED Posted: by rqomsiya

@sepiemoini Does this process allow for no user interaction when FV2 is enabled? I've noticed that with the CreateOSXinstallpkg process, if I have FV2 enabled, the user needs to authenticate after a restart.

Like
SOLVED Posted: by rqomsiya

Disregard. I just re-read the Github readme. No user interaction required !! :)

Like
SOLVED Posted: by DanJ_LRSFC

@roiegat I've followed that guide (though I skipped the bit about extra packages as I don't need anything else to be installed), however nothing seems to be happening after reboot, it just goes to the 10.10 login window. I want to do it using Casper Remote rather than Self Service, so I removed the user interaction bits from the script, that shouldn't make a difference?

@sepiemoini That Rosko script seems to be for going from 10.11 to 10.12? I'm wanting to go from 10.10 to 10.11.

@tak10 I'll try this method instead as the createOSInstallPkg method does not seem to be working for me.

EDIT: @tak10's method seems to be working as I am seeing the OS install screen now. Thanks for the help everyone!

Like
SOLVED Posted: by sepiemoini

@DanJ_LRSFC @Rosko's method works for 10.10! I imagine it'll work for earlier releases as well and plan to test it on 10.9 today. We don't have too many legacy macOS devices so I am only concerned primarily with 10.10-10.11.

Like
SOLVED Posted: by roiegat

@DanJ_LRSFC I usually tell it to reboot to the installer partition. It's part of the reboot settings.

Like
SOLVED Posted: by SGill

createOSInstallPkg worked fine with no user interaction here in testing yesterday. I did end up having to specify a restart however, as the pkg it generates does not appear to have that built-in.

Like
SOLVED Posted: by Rosko

Good day all!

@DanJ_LRSFC The solved post will work until you are looking to upgrade to 10.12 which is where the rules of the game got changed. Then you will need to utilize the startosinstall binary if you want to have a complete in-place upgrade that has no user interaction which is what I did in my workflow. This workflow should work for any previous OS upgrades as well, just wasn't required.

I've also tested with the createOSInstallPkg, but had issues with authenticated reboots not processing correctly which is why I wrote up this workflow.

Like
SOLVED Posted: by sepiemoini

Three cheers for @Rosko's tried and true method!

Like
SOLVED Posted: by roiegat

@Rosko I'll second that cheer. Testing out the method now and it's smooth so far. Will have to add a policy after the install is finished to clean off that installer package.

Like
SOLVED Posted: by Rosko

@roiegat You could also add something like this to the same script ;)

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
# CREATE FIRST BOOT SCRIPT
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 

/bin/mkdir /usr/local/jamfps

/bin/echo "#!/bin/bash
## First Run Script to Install Profile to Skip iCloud and Siri
## then cleanup the files.

## Install mobileconfig profiles
/usr/bin/profiles -I -F /Users/Shared/SkipiCloudSetup.mobileconfig
/usr/bin/profiles -I -F /Users/Shared/SkipSiriSetup.mobileconfig
/bin/sleep 3

## Clean up files
/bin/rm -fdr /Users/Shared/Install\ macOS\ Sierra.app
/bin/rm -fdr /Users/Shared/SkipiCloudSetup.mobileconfig
/bin/rm -fdr /Users/Shared/SkipSiriSetup.mobileconfig
/bin/sleep 2

## Remove LaunchDaemon
/bin/launchctl unload -w /Library/LaunchDaemons/com.jamfps.installProfiles.plist
/bin/rm -f /Library/LaunchDaemons/com.jamfps.installProfiles.plist

## Reset cfprefsd
/usr/bin/killall cfprefsd

exit 0" > /usr/local/jamfps/finishOSInstall.sh

/usr/sbin/chown root:admin /usr/local/jamfps/finishOSInstall.sh
/bin/chmod 755 /usr/local/jamfps/finishOSInstall.sh

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
# LAUNCH DAEMON
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 

/bin/echo "<?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.jamfps.installProfiles</string> 
    <key>ProgramArguments</key> 
    <array> 
        <string>/usr/local/jamfps/finishOSInstall.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict> 
</plist>" > /Library/LaunchDaemons/com.jamfps.installProfiles.plist

##Set the permission on the file just made.
/usr/sbin/chown root:wheel /Library/LaunchDaemons/com.jamfps.installProfiles.plist
/bin/chmod 644 /Library/LaunchDaemons/com.jamfps.installProfiles.plist

Something similar to this will be added to the GitHub version when I get time. Won't include the mobileconfig profiles, but otherwise I will basically be adding that verbatim.

Like
SOLVED Posted: by sepiemoini

While @Rosko's post-install script is probably infinitely better, I have include the following into my organization.

#!/bin/bash
#macOS Sierra (Post-Install) Script:

# Remove "Install macOS Sierra.app" installer from /Users/Shared/.
rm -rf /Users/Shared/Install\ macOS\ Sierra.app; 

exit 0;
Like
SOLVED Posted: by Rosko

Nice job @sepiemoini! All that matters is we are able to accomplish what we set out to do :)

Also, I had a few minutes, so I did go ahead and update the GitHub repo with the first boot script pieces.

Like
SOLVED Posted: by csanback

@sepiemoini Would you mind sharing your quit common applications script? We are doing something very similar to your setup, and wanted to compare.

Like
SOLVED Posted: by sepiemoini

@csanback Sure! Fair warning that it's SUPER basic and could be customized to your liking.

#!/bin/bash

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
#  Quit Common Applications
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 

osascript -e 'quit app "Firefox"'
osascript -e 'quit app "Google Chrome"'
osascript -e 'quit app "Safari"'
osascript -e 'quit app "iTunes"'
osascript -e 'quit app "Slack"'
osascript -e 'quit app "Excel"'
osascript -e 'quit app "Outlook"'
osascript -e 'quit app "PowerPoint"'
osascript -e 'quit app "Word"'

exit 0

I am sure that there are much simpler methods to achieve the same goal but this is working for my organization. I prioritized closing browsers and Office 2016 and added Slack and iTunes as they're sluggish. It's worth noting that in my Self Service description (set that users have to view it), it states that all work should be saved, blah, blah, blah. You can even use Automator (/Applications/Utilities/Automator.app) to create a custom app that closes EVERYTHING except Self Service for instance.

Like
SOLVED Posted: by dpertschi

@Rosko Nice work, the first boot script is the icing! That recon at first boot is critical.

Like
SOLVED Posted: by dpertschi

@Rosko So the first few tests I ran with this script I'm seeing the installer app delete as expected, but the recon and LD delete is not happening.

Nothing obvious in the logging. Any thoughts on that?

Like
SOLVED Posted: by mpermann

@Rosko I'm seeing similar issue as @dpertschi. The LD still exists on the system when the process is finished but I don't think it's loaded. I'm not sure if the recon is happening either. The workflow on my test VMs has the computer reboot about half way through and it's at that point that I see the JSS notify me that the computer has fallen out of one smart group and into another. I guess I would expect the recon to happen after the installation is fully completed. I'll do some more testing and add some logging statements to see if I can figure out what is and isn't happening. Otherwise this workflow is quite nice. Thanks for sharing it!

Edit: I forgot to mention that the finishOSInstall.sh script is also in /usr/local/jamfps. I'm not sure if that is supposed to be deleted at some point or not.

Like
SOLVED Posted: by __Uss

@Rosko @sepiemoini awesome work guys!!!!!

Like
SOLVED Posted: by sepiemoini

Thanks, @__Uss! I've even added a jamfHelper notification for users running once daily to encourage the upgrade.

Like
SOLVED Posted: by kcgarner

@sepiemoini

would you mind sharing your jamfHelper notification to encourage the upgrade.

Like
SOLVED Posted: by rodders

@sepiemoini Id also like to see that JAMFhelper code for the above.
Cheers!

Like
SOLVED Posted: by nberanger

@sepiemoini Nice work on the jamfHelper notification. I would love to take a look at your code as well.

Like
SOLVED Posted: by allanp81

This script works great...apart from that we restrict staff from running the install app so it fails. Is there anyway we can bypass this restriction or do you think just renaming the install app would be enough?

Like
SOLVED Posted: by mm2270

@allanp81 I'm not sure what you mean. If you're referring to @Rosko's upgrade method, it doesn't/shouldn't run afoul of most Restricted Software settings, unless you somehow added in the startosinstall process to be blocked. His script does not call the application bundle directly, it calls that binary, which is inside the app and allows for the upgrade to start without running the full application. You shouldn't be seeing it get blocked, unless you have some very specific and unusual restrictions in place.

Like
SOLVED Posted: by allanp81

Hmm, that's odd then as it seems to get blocked. Will have a proper look into it tomorrow.

Like
SOLVED Posted: by sdagley

@mm2270 & @allanp81 If you have the process named "Install macOS Mojave.app" in a Restricted Software configuration it will cause startosinstall to fail when it tries to start the helper app it uses. <VoiceOfExperience/>

Like
SOLVED Posted: by mm2270

@sdagley Ok, interesting. Thanks for that info. I believe that's why I've never had an issue with it. I have always only blocked the InstallAssistant executable, which is what gets run when double clicking the app installer. Using the full install app bundle name for Restricted Software is folly in my opinion as it's stupidly easy to get around it by renaming the app bundle even with just one character difference.

If there's a need to keep that "Install macOS Mojave.app" restriction in place until upgrade time, my recommendation would be to drop a breadcrumb of some kind on the machines that are prepped for the upgrade, use an Extension Attribute to track the presence of that file and a corresponding Smart Group. So meaning, make a Smart Group like "Mojave Upgrade Ready" that only contains machines with the requisite hidden file or preference setting in place. Then use that group as an Exclusion to the Mojave Restricted Software item. You will have to have something do a recon or jamf policy on those machines to make sure the restriction gets removed from them. Once it does, the OSUpgrade script should work fine.

Like
SOLVED Posted: by sdagley

@mm2270 Thanks for the hint on blocking InstallAssistant instead of the Install macOS XXX.app, I'm going to give it a try. With non-admin users I'm not too worried about the app being renamed to bypass the block, rather I like the idea of one restriction for all of the macOS install GUI versions. For users with admin rights it's easy enough for them to find documentation on startosinstall so blocking InstallAssistant is also pretty easy to bypass. My hope is all will take the easy way through Self Service.

BTW, I have used the breadcrumb approach to exclude members of the Smart Group from a Restricted Software configuration, but it's also been my experience that restriction removal is not always reliable even with multiple restarts, check-in, and recons. Running jamf manage usually works though.

Like