Jamf Pro; Upgrade methods for Mojave.

ThijsX
Valued Contributor
Valued Contributor

Hi All,

Lets share idea's about how to upgrade to macOS Mojave via;

  • Self Service
  • App Store
  • Others

Also an idea to share idea's an how to upgrade from 10.14.1 to 10.14.2 due the new Software Update pane in Sysprefs.

Cheers.

110 REPLIES 110

boon12345
New Contributor

Hopefully these installation instructions will be of use to some of you. Obviously just change the High Sierra names to Mojave:

Upgrading to macOS High Sierra

Requirements
• A copy of Install macOS High Sierra.app from the Mac App Store
Note : This has been tested on macOS 10.10.5, 10.11.5 & 10.12.5 upgrading to 10.12.6 and 10.13.3

• This script: https://github.com/kc9wwh/macOSUpgrade
• Jamf Pro Applications
o Composer.app
o Jamf Admin.app

  1. Login to the Jamf Pro Server
  2. Create a new Computer SmartGroup called High Sierra “Cached”
    a. Criteria Tab
    i. Application Title ‘has’ Install macOS High Sierra.app

  3. Create a new Computer SmartGroup called High Sierra Ready
    a. Criteria Tab
    i. Operating System Version ‘is’ 10.10.5 OR 10.11.5 OR 10.12.5

  4. Now we need to upload the Install macOS High Sierra Script from GitHub into the Jamf Pro Server: a. Gear Icon > Computer Management > Scripts > Create new Script called macOS10.13Upgrade
    b. Paste the contents of the script into the Script Tab
    c. Save

  5. Open Composer.app on computer that has a copy of the Install macOS High Sierra.app
    i. NOTE: This step needs to be performed on a 10.12 or older machine that is still on the HFS filesystem. This is because an HFS file system can’t mount an APFS formatted DMG. If you make this on a 10.13 machine, it will format the DMG as APFS.
    b. Drag the Install macOS High Sierra.app into the left side of Composer.
    c. Build as DMG and place on the desktop
    i. I named mine macOS High Sierra.dmg

  6. Open Jamf Admin.app
    a. Drag the macOS High Sierra.dmg we just made in Composer into Jamf Admin from the Desktop
    b. Assign it a category and set it to a priority of 1
    c. Save

  7. Create a policy called “Cache” High Sierra
    a. Configure Packages Payload
    i. Select the macOS High Sierra.dmg package we just made in Composer
    ii. Keep the “Action to take on computers” to Install

  8. We are “caching” OR placing a copy of Install macOS High Sierra.app in the /Applications/ folder.
    b. Configure a Maintenance Payload i. Update Inventory
    c. TESTING ONLY - Do NOT set a trigger
    d. TESTING ONLY - Execution Frequency – Ongoing
    e. TESTING ONLY - Make available in Self Service
    f. Scope to group of TESTING computers that are not High Sierra.

    • TESTING * - Open Self Service.app on one of the TESTING computers a. Run the policy “Cache” High Sierra i. This will place Install macOS High Sierra.app in /Applications ii. If that worked, move onto the next step. If it did not, then begin to troubleshoot.
  9. Create a second policy called Upgrade to macOS High Sierra
    a. Configure the Script Payload
    i. Select the macOS10.13Upgrade script
    ii. Enter /Applications/Install macOS High Sierra.app in Parameter 4
    iii. Enter OS Version Number the machine is going to in Parameter 5
    iv. Enter Customer trigger in Parameter 6 if applicable
    b. Configure a Maintenance Payload i. Update Inventory
    c. Testing & Production - Do NOT set a trigger
    d. Testing & Production - Execution Frequency – Ongoing
    e. Testing & Production - Make Available in Self Service
    i. Make sure you put in a disclaimer that the upgrade will take around 30-45 minutes and that Users should save all their work. Users will NOT be able to use their computer during this time.
    ii. Check the box that makes the Users “View the disclaimer”
    iii. Check the box that features the policy on the main page
    f. Scope to Computer SmartGroup High Sierra “Cached”

  10. If we can verify the “Cache” High Sierra policy places Install macOS High Sierra.app in /Applications and the Upgrade to macOS High Sierra policy executes the script that runs the macOS High Sierra installer, we can change the “Cache” High Sierra policy to:
    a. Trigger – Recurring Check-In
    b. Execution Frequency – Once per computer
    c. Self Service – Uncheck box to remove from Self Service
    d. Scope – Remove TESTING computers, and add High Sierra Ready Computer SmartGroup

tnielsen
Valued Contributor

@szultzie

You have filevault on I assume? That's why. The setup utility cannot unlock the volume for the user, the user must do it. There's no easy way around that I'm afraid. The users must wait.

szultzie
Contributor II

@tnielsen No Filevault in my testing. But maybe your referring to someone else's scenario?

szultzie
Contributor II

I get the following screen after an update is complete and i log in for the first time

14edcd895fd343eb85b678925babcaca

then

17c805f985b14f25ab14ea59f5803bcd
and finally this

46734fa3b3574a9aa1b91e880dc8d392

The last two im sure I can get around somehow, but i don't like that it reboots the computer after first log in, after an in place upgrade, I cant automate that for a Lab environment.

-Peter

daniel_hayden
New Contributor III

@kcsantos @MTFMRCO Beware of copy/paste..check the code as pasted. I found by just pasting the script as is resulted in an issue with the plist not being created properly, Apparently there is a wayward space after the final EOL/EOF/EOP that is preventing the files from being created correctly and /bin/mkdir -p /usr/local/jamfps also contains a wayward space after jamfps

Running snippet in CodeRunner as pasted with space still present after EOP:

/bin/cat << EOP > /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist
<?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.apple.install.osinstallersetupd</string> <key>LimitLoadToSessionType</key> <string>Aqua</string> <key>MachServices</key> <dict> <key>com.apple.install.osinstallersetupd</key> <true/> </dict> <key>TimeOut</key> <integer>300</integer> <key>OnDemand</key> <true/> <key>ProgramArguments</key> <array> <string>$OSInstaller/Contents/Frameworks/OSInstallerSetup.framework/Resources/$progArgument</string> </array>
</dict>
</plist>
EOP

Resulted in this output

<?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.apple.install.osinstallersetupd</string> <key>LimitLoadToSessionType</key> <string>Aqua</string> <key>MachServices</key> <dict> <key>com.apple.install.osinstallersetupd</key> <true/> </dict> <key>TimeOut</key> <integer>300</integer> <key>OnDemand</key> <true/> <key>ProgramArguments</key> <array> <string>/Contents/Frameworks/OSInstallerSetup.framework/Resources/</string> </array>
</dict>
</plist>
EOP

Running again after removing the space from pasted code resulted in the EOP not being part of the plist

<?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.apple.install.osinstallersetupd</string> <key>LimitLoadToSessionType</key> <string>Aqua</string> <key>MachServices</key> <dict> <key>com.apple.install.osinstallersetupd</key> <true/> </dict> <key>TimeOut</key> <integer>300</integer> <key>OnDemand</key> <true/> <key>ProgramArguments</key> <array> <string>/Contents/Frameworks/OSInstallerSetup.framework/Resources/</string> </array>
</dict>
</plist>

danshaw
Contributor II

Has anyone worked into their workflow a good way to have the computer being upgraded get the necessary kernel extensions before the computer boots up with the new OS? I find that if I scope the Kext's to a smartgroup looking at a users OS, it most of the time is too late to the party and the user has already logged in and see's the warning messages.

I talked to JAMF support and they said it wouldn't work to push the config profiles to the computers before they're upgraded so somehow it needs to be done after the upgrade, but before the user logs in.

Curious how you all are doing it.

I'm currently testing the macOSUpgrade script and would like to use it if possible.

steve_summers
Contributor III

Hey @danshaw, maybe you can try this. It actually fixed a couple Config Profile failures I was having. A fellow MacAdmin on Slack suggested doing this:
-Create a smart group (named whatever) and as the criteria, have this:Profile Name Has Privacy Preferences Policy Control. (My smart group has Last check in less than 15 days and that PPPC setting...that's it)

When a Mac upgrades to Mojave, that PPPC profile comes down automatically. I then scope that smart group to other config profiles I want, such as the whitelisting profiles we are all dealing with. That PPPC profile group acts like a trigger to enable other profiles scoped to it to come down, see? So you could use that smart group as a target with your Kext Profile, so if it 1) upgrades to Mojave then 2) gets the PPPC profile (which it will), then whatever profiles scoped to that smart group get triggered. I hope that helps. I have that workflow and it's not causing any issues.

billystanton29
New Contributor II

We are also seeing the "osinstallersetupd" prompt, even using the newer script.

Any thoughts?

hpavlic_
New Contributor III

@billystanton29

I also got the prompt even if we do not run FV2 so I just edited the script so it gives admin rights to all users prior to the upgrade if they are not admins.

/usr/bin/dscl . read /Groups/admin GroupMembership |  tr ' ' '
' | grep -x "$currentUser"
if [[ $? -ne 0 ]] ; then
        /bin/echo "User is not an Admin.  Adding $currentUser to Admin group"
        /usr/sbin/dseditgroup -o edit -a "$currentUser" -t user admin
        /bin/echo "Demote token file added for $currentUser at $currentUserHomeDirectory/.demoteafterupgrade"
        /usr/bin/touch "$currentUserHomeDirectory"/.demoteafterupgrade
fi

@kcsantos @MTFMRCO

I have noticed that as well and found a solution.
The problem was that the LaunchDaemon is launched during startup as root and it cannot detect currently logged on user.
That is why I have added the part to finishOSInstall.sh at the start to check when the dock becomes active and then runs the rest:

while true; do
    myUser=`whoami`
    dockcheck=`ps -ef | grep [/]System/Library/CoreServices/Dock.app/Contents/MacOS/Dock`
    if [ ! -z "${dockcheck}" ]; then
        echo "Dockcheck is ${dockcheck}, breaking."
        break
    fi
    sleep 1
done

Hope that helps :)

FutureFacinLuke
Contributor II

I have two methods for this, but also run into the reboot problem faced by @szultzie

For a clean install on non T2 macs I use DeployStudio to image to the last version of 10.12.6, then install the Instal MacOS [Version}.app to /Applications and run startosinstall with --agreetolicense --nointeraction, I don't convert to APFS. This method works for Non-Fusion Macs but I converted them to APFS during the High Sierra update so this year I can use --eraseinstall

The other method I used was to Package the MacOS.app and script that, two policies for Fusion and non fusion scoped accordingly and installed by a common custom trigger. Now that Mojave supports APFS Fusion Drives they will get converted when upgraded so that's my 2020 vision, DeployStudio will be decommissioned and all builds will be (as close as possible to) zero touch DEP then JAMF'd.

The downside to --eraseinstall is that it will not run if the MacOS.app is older than the installed build, so you either need to keep your .app package updated or download it on the fly as per https://grahamrpugh.com/2018/03/26/reinstall-macos-from-system-volume.html.

fishbackn
New Contributor

FYI, guys the startosinstall "--applicationpath " variable has been depreciated in Mojave. I ran into issues when including that in the startosinstall command for Mojave. I also had to add a "--newvolumename" variable for the Mojave install as well.

billystanton29
New Contributor II

@hpavlic. thank you!

I've added this, and Mojave installed successfully.. unfortunately the end user is still an admin after install, and the laptop has forgotten our staff WiFi network (we push the SSID and password via a Config Profile)

Any thoughts on how we might resolve this?

Thanks so much!

ThijsX
Valued Contributor
Valued Contributor

Awesome to see al that help in this community! i am still using a huge part of @bpavlov his work! currently migrated 300+- devices from 10.13.4/5/6 to 10.14.0/1 and less that 10 IT tickets!

hpavlic_
New Contributor III

@billystanton29

Did you also add the part I mentioned to finishOSInstall.sh ?

Also, in there there is a line

## Update Device Inventory
/usr/local/jamf/bin/jamf recon

You can add after that something like

## Running manage
/usr/local/jamf/bin/jamf manage

So that way it will run "jamf manage" after recon to pull the Configuration Profile to the machine.

Let me know if it worked.

billystanton29
New Contributor II

@hpavlic.

Issue with the Admin rights is resolved now thank you :-)

The WiFi issue still persists though.. The machine already has the WiFi policy, and strangely enough I can see the WiFi SSID in the "remembered networks".

A restart of the Mac still doesn't pick it up.

If I exclude the user from the profile, and then re-scope it to them then it works perfectly, but this relies on them having an ethernet connection which some of our users don't have. (The profile is computer level, should it be user level maybe?)

The SSID is hidden, so I'm wondering if this is stopping the Mac from finding the network and auto-joining?

Sorry, I'm a bit stuck! - Thanks once again for your help on this!

hpavlic_
New Contributor III

@billystanton29

I'm guessing that you have AD certificate payload since it requires them to be connected to wired network ....
We have AD cert. payload and I didn't notice that users lost their preferred network or conf. profile...

Do you have a specific scope for that Configuration Profile or specific setting in it that can maybe interfere during installation/restart?

billystanton29
New Contributor II

@hpavlic.

I don't believe we have an AD Cert.

We bind to AD manually during laptop setup (Though create mobile accounts)

Our WiFi profile is set to All Users / All Computers and Auto Join and Hidden Network are both ticked.

It's almost like the Mac forgets that it knows those WiFi details until we remind it by either manually entering it, or removing and re-adding the WiFi profile for that machine.

Is there a way we can get JAMF to re-push the WiFi profile out again after the upgrade is finished, without us having to manually exclude and re-add users from the policy each time?

jlang_remedy
New Contributor III

@hpavlic. Can you post the full version of your modified upgrade script that includes the promotion of user to admin and the finishOSinstall.sh extra bits. Just want unavoid issues trying to edit the wrong places, so i can test.

Also does your edited script reverse reverting the current user to standard? In our case we typically have a standard account, a local admin account, and the admin jamf management account in place on all machines. Just want to make sure post-upgrade, everyone's privilege level remains the same.

hpavlic_
New Contributor III

@billystanton29

hmmm that is weird, I tried to set-up profile re-push so many times but it is tricky, mostly because we use AD certificates for Wi-Fi authentication so it is hard (Conf. profile fails if user is not on wired and the only way to re push was to have user connected via wire and then run removeMDM profile, Jamf manage and it is a messy situation).

What I can recommend is creating a dummy file somewhere on the Mac and then compile EA that will read if the file is present.
Then create Smart Computer Group that detects if file is present (based on EA) and put that group in Exclusion for the scope of the configuration profile.
So the process would be something like a script which will do the following:
1. Create dummy file
2. run "Jamf recon" and "Jamf Manage"
3. Delete dummy file
4. run "recon" and "manage"
And it gets more complicated if you want to have a detection method to see if conf. profile is present after.

@jlang_remedy

Sure I can share, I have modified some stuff so please take this in consideration:

  1. This script will not check if AC is connected, it will check if the battery is more than 80% (reason behind that is: most of our users tend to be wireless, not plugged in etc. and we are planning to use the same script for push later on. While testing we noticed that during the upgrade battery is drained for 30-40% so we should be fine with battery level higher than 80%)

  2. On line 228, we only put 10GB as required space, Apple recommends 8,something.

  3. Yes, the adding user to admin group is part of the script and it will add user that is currently running the Policy as admin, create dummy file and remove them after reboot.

Please note that I noticed some minor flaws in this design and will try to fix them when I get the time.
Flaw is that LaunchDaemon is started when user logs in, ANY user. So if you run the policy as let's say John, John will get Admin rights, machine starts the upgrade, restarts, you are staring at the logon screen and log in as Administrator or for example Mary, LaunchDaemon will run, see that Administrator or Mary do not have the dummy file, run the rest of the script and self-destruct meaning that when John logs in he will still be administrator.
It would be better to put in the script that it searches for dummy file, find what user has it and demotes them, but need to work it out and find best approach.

Also, since we do not have FV2 enabled, didn't yet test this script against encrypted machines, so please test it out before going into production.

Here is the script:

#!/bin/bash

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Copyright (c) 2018 Jamf.  All rights reserved.
#
#       Redistribution and use in source and binary forms, with or without
#       modification, are permitted provided that the following conditions are met:
#               * Redistributions of source code must retain the above copyright
#                 notice, this list of conditions and the following disclaimer.
#               * Redistributions in binary form must reproduce the above copyright
#                 notice, this list of conditions and the following disclaimer in the
#                 documentation and/or other materials provided with the distribution.
#               * Neither the name of the Jamf nor the names of its contributors may be
#                 used to endorse or promote products derived from this software without
#                 specific prior written permission.
#
#       THIS SOFTWARE IS PROVIDED BY JAMF SOFTWARE, LLC "AS IS" AND ANY
#       EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#       WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#       DISCLAIMED. IN NO EVENT SHALL JAMF SOFTWARE, LLC BE LIABLE FOR ANY
#       DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
#       (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
#       LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#       ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#       (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#       SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# This script was designed to be used in a Self Service policy to ensure specific
# requirements have been met before proceeding with an inplace upgrade of the macOS,
# as well as to address changes Apple has made to the ability to complete macOS upgrades
# silently.
#
# VERSION: v2.7.2.1
#
# REQUIREMENTS:
#           - Jamf Pro
#           - macOS Clients running version 10.10.5 or later
#           - macOS Installer 10.12.4 or later
#           - eraseInstall option is ONLY supported with macOS Installer 10.13.4+ and client-side macOS 10.13+
#           - Look over the USER VARIABLES and configure as needed.
#
#
# For more information, visit https://github.com/kc9wwh/macOSUpgrade
#
#
# Written by: Joshua Roskos | Jamf
#
# Created On: January 5th, 2017
# Updated On: September 28th, 2018
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# USER VARIABLES
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

##Specify path to OS installer. Use Parameter 4 in the JSS, or specify here
##Example: /Applications/Install macOS High Sierra.app
OSInstaller="$4"

##Version of Installer OS. Use Parameter 5 in the JSS, or specify here.
##Example Command: /usr/libexec/PlistBuddy -c 'Print :"System Image Info":version' "/Applications/Install macOS High Sierra.app/Contents/SharedSupport/InstallInfo.plistr"
##Example: 10.12.5
version="$5"
versionMajor=$( /bin/echo "$version" | /usr/bin/awk -F. '{print $2}' )
versionMinor=$( /bin/echo "$version" | /usr/bin/awk -F. '{print $3}' )

##Custom Trigger used for download. Use Parameter 6 in the JSS, or specify here.
##This should match a custom trigger for a policy that contains just the 
##MacOS installer. Make sure that the policy is scoped properly
##to relevant computers and/or users, or else the custom trigger will
##not be picked up. Use a separate policy for the script itself.
##Example trigger name: download-sierra-install
download_trigger="$6"

##MD5 Checksum of InstallESD.dmg
##This variable is OPTIONAL
##Leave the variable BLANK if you do NOT want to verify the checksum (DEFAULT)
##Example Command: /sbin/md5 /Applications/Install macOS High Sierra.app/Contents/SharedSupport/InstallESD.dmg
##Example MD5 Checksum: b15b9db3a90f9ae8a9df0f81741efa2b
installESDChecksum="$7"

##Valid Checksum?  O (Default) for false, 1 for true.
validChecksum=0

##Unsuccessful Download?  0 (Default) for false, 1 for true.
unsuccessfulDownload=0

##Erase & Install macOS (Factory Defaults)
##Requires macOS Installer 10.13.4 or later
##Disabled by default
##Options: 0 = Disabled / 1 = Enabled
##Use Parameter 8 in the JSS.
eraseInstall="$8"
if [[ "${eraseInstall:=0}" != 1 ]]; then eraseInstall=0 ; fi
#macOS Installer 10.13.3 or ealier set 0 to it.
if [ "$versionMajor${versionMinor:=0}" -lt 134 ]; then
    eraseInstall=0
fi

##Enter 0 for Full Screen, 1 for Utility window (screenshots available on GitHub)
##Full Screen by default
##Use Parameter 9 in the JSS.
userDialog="$9"
if [[ ${userDialog:=0} != 1 ]]; then userDialog=0 ; fi

##Title of OS
##Example: macOS High Sierra
macOSname=$(/bin/echo "$OSInstaller" | /usr/bin/sed 's/^/Applications/Install (.*).app$/1/')

##Title to be used for userDialog (only applies to Utility Window)
title="$macOSname Upgrade"

##Heading to be used for userDialog
heading="Please wait as we prepare your computer for $macOSname..."

##Title to be used for userDialog
description="This process will take approximately 5-10 minutes.
Once completed your computer will reboot and begin the upgrade."

##Description to be used prior to downloading the OS installer
dldescription="We need to download $macOSname to your computer, this will 
take several minutes."

##Jamf Helper HUD Position if macOS Installer needs to be downloaded
##Options: ul (Upper Left); ll (Lower Left); ur (Upper Right); lr (Lower Right)
##Leave this variable empty for HUD to be centered on main screen
dlPosition="ul"

##Icon to be used for userDialog
##Default is macOS Installer logo which is included in the staged installer package
icon="$OSInstaller/Contents/Resources/InstallAssistant.icns"

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# FUNCTIONS
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

downloadInstaller() {
    /bin/echo "Downloading macOS Installer..."
    /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper 
        -windowType hud -windowPosition $dlPosition -title "$title" -alignHeading center -alignDescription left -description "$dldescription" 
        -lockHUD -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/SidebarDownloadsFolder.icns" -iconSize 100 &
    ##Capture PID for Jamf Helper HUD
    jamfHUDPID=$!
    ##Run policy to cache installer
    /usr/local/jamf/bin/jamf policy -event "$download_trigger"
    ##Kill Jamf Helper HUD post download
    /bin/kill "${jamfHUDPID}"
}

verifyChecksum() {
    if [[ "$installESDChecksum" != "" ]]; then
        osChecksum=$( /sbin/md5 -q "$OSInstaller/Contents/SharedSupport/InstallESD.dmg" )
        if [[ "$osChecksum" == "$installESDChecksum" ]]; then
            /bin/echo "Checksum: Valid"
            validChecksum=1
            return
        else
            /bin/echo "Checksum: Not Valid"
            /bin/echo "Beginning new dowload of installer"
            /bin/rm -rf "$OSInstaller"
            /bin/sleep 2
            downloadInstaller
        fi
    else
        ##Checksum not specified as script argument, assume true
        validChecksum=1
        return
    fi
}

cleanExit() {
    /bin/kill "${caffeinatePID}"
    exit "$1"
}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# SYSTEM CHECKS
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

##Caffeinate
/usr/bin/caffeinate -dis &
caffeinatePID=$!

##Get Current User
currentUser=$( /usr/bin/stat -f %Su /dev/console )

##Get Current Users homefolder
currentUserHomeDirectory=$( /usr/bin/dscl . -read "/users/$currentUser" NFSHomeDirectory | cut -d " " -f 2 )

##Check if current user is an admin
/usr/bin/dscl . read /Groups/admin GroupMembership |  tr ' ' '
' | grep -x "$currentUser"
if [[ $? -ne 0 ]] ; then
        /bin/echo "User is not an Admin.  Adding $currentUser to Admin group"
        /usr/sbin/dseditgroup -o edit -a "$currentUser" -t user admin
        /bin/echo "Demote token file added for $currentUser at $currentUserHomeDirectory/.demoteafterupgrade"
        /usr/bin/touch "$currentUserHomeDirectory"/.demoteafterupgrade
fi

##Check if FileVault Enabled
fvStatus=$( /usr/bin/fdesetup status | head -1 )

## Check if battery is below 80%
battLevel=$( pmset -g ps  |  sed -n 's/.*[[:blank:]]+*(.*%).*/1/p' )
if [[ ${battLevel} > *"80"* ]]; then
    pwrStatus="OK"
    /bin/echo "Power Check: OK - Battery above 80%"
else
    pwrStatus="ERROR"
    /bin/echo "Power Check: ERROR - Battery level below 80%"
fi


##Check if free space > 10GB
osMajor=$( /usr/bin/sw_vers -productVersion | /usr/bin/awk -F. '{print $2}' )
osMinor=$( /usr/bin/sw_vers -productVersion | /usr/bin/awk -F. '{print $3}' )
if [[ $osMajor -eq 12 ]] || [[ $osMajor -eq 13 && $osMinor -lt 4 ]]; then
    freeSpace=$( /usr/sbin/diskutil info / | /usr/bin/grep "Available Space" | /usr/bin/awk '{print $6}' | /usr/bin/cut -c 2- )
else
    freeSpace=$( /usr/sbin/diskutil info / | /usr/bin/grep "Free Space" | /usr/bin/awk '{print $6}' | /usr/bin/cut -c 2- )
fi

if [[ ${freeSpace%.*} -ge 10000000000 ]]; then
    spaceStatus="OK"
    /bin/echo "Disk Check: OK - ${freeSpace%.*} Bytes Free Space Detected"
else
    spaceStatus="ERROR"
    /bin/echo "Disk Check: ERROR - ${freeSpace%.*} Bytes Free Space Detected"
fi

##Check for existing OS installer
loopCount=0
while [[ $loopCount -lt 3 ]]; do
    if [ -e "$OSInstaller" ]; then
        /bin/echo "$OSInstaller found, checking version."
        OSVersion=$(/usr/libexec/PlistBuddy -c 'Print :"System Image Info":version' "$OSInstaller/Contents/SharedSupport/InstallInfo.plist")
        /bin/echo "OSVersion is $OSVersion"
        if [ "$OSVersion" = "$version" ]; then
          /bin/echo "Installer found, version matches. Verifying checksum..."
          verifyChecksum
        else
          ##Delete old version.
          /bin/echo "Installer found, but old. Deleting..."
          /bin/rm -rf "$OSInstaller"
          /bin/sleep 2
          downloadInstaller
        fi
        if [ "$validChecksum" == 1 ]; then
            unsuccessfulDownload=0
            break
        fi
    else
        downloadInstaller
    fi

    unsuccessfulDownload=1
    ((loopCount++))
done

if (( unsuccessfulDownload == 1 )); then
    /bin/echo "macOS Installer Downloaded 3 Times - Checksum is Not Valid"
    /bin/echo "Prompting user for error and exiting..."
    /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -icon "$icon" -heading "Error Downloading $macOSname" -description "We were unable to prepare your computer for $macOSname. Please contact the IT Support Center." -iconSize 100 -button1 "OK" -defaultButton 1
    cleanExit 0
fi


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

/bin/mkdir -p /usr/local/jamfps

/bin/cat > /usr/local/jamfps/finishOSInstall.sh <<'EOL'
#!/bin/bash

## Wait for Dock
while true; do
    myUser=`whoami`
    dockcheck=`ps -ef | grep [/]System/Library/CoreServices/Dock.app/Contents/MacOS/Dock`
    if [ ! -z "${dockcheck}" ]; then
        echo "Dockcheck is ${dockcheck}, breaking."
        break
    fi
    sleep 1
done

##Demote if user was not an admin before upgrade
##Get Current User
currentUser=$( /usr/bin/stat -f %Su /dev/console )

##Get Current Users homefolder
currentUserHomeDirectory=$( /usr/bin/dscl . -read "/users/$currentUser" NFSHomeDirectory | cut -d " " -f 2 )
if [[ -e "$currentUserHomeDirectory"/.demoteafterupgrade ]] ; then
    /bin/echo "User was not an Admin before upgrade, Removing $currentUser from Admin group"
    dseditgroup -o edit -d "$currentUser" -t user admin
    /bin/echo "Demote token file removed for $currentUser at $currentUserHomeDirectory/.demoteafterupgrade"
    rm -f "$currentUserHomeDirectory"/.demoteafterupgrade
fi

## First Run Script to remove the installer.
## Clean up files
/bin/rm -fr "$OSInstaller"
/bin/sleep 2

## Update Device Inventory
/usr/local/jamf/bin/jamf recon

## Remove LaunchDaemon
/bin/rm -f /Library/LaunchDaemons/com.jamfps.cleanupOSInstall.plist

## Remove Script
/bin/rm -fr /usr/local/jamfps

exit 0
EOL

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

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

/bin/cat << EOF > /Library/LaunchDaemons/com.jamfps.cleanupOSInstall.plist
<?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.cleanupOSInstall</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>-c</string>
        <string>/usr/local/jamfps/finishOSInstall.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
EOF

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

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# LAUNCH AGENT FOR FILEVAULT AUTHENTICATED REBOOTS
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

##Determine Program Argument
if [[ $osMajor -ge 11 ]]; then
    progArgument="osinstallersetupd"
elif [[ $osMajor -eq 10 ]]; then
    progArgument="osinstallersetupplaind"
fi

/bin/cat << EOP > /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist
<?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.apple.install.osinstallersetupd</string>
    <key>LimitLoadToSessionType</key>
    <string>Aqua</string>
    <key>MachServices</key>
    <dict>
        <key>com.apple.install.osinstallersetupd</key>
        <true/>
    </dict>
    <key>TimeOut</key>
    <integer>300</integer>
    <key>OnDemand</key>
    <true/>
    <key>ProgramArguments</key>
    <array>
        <string>$OSInstaller/Contents/Frameworks/OSInstallerSetup.framework/Resources/$progArgument</string>
    </array>
</dict>
</plist>
EOP

##Set the permission on the file just made.
/usr/sbin/chown root:wheel /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist
/bin/chmod 644 /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# APPLICATION
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

if [[ ${pwrStatus} == "OK" ]] && [[ ${spaceStatus} == "OK" ]]; then
    ##Launch jamfHelper
    if [ ${userDialog} -eq 0 ]; then
        /bin/echo "Launching jamfHelper as FullScreen..."
        /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -title "" -icon "$icon" -heading "$heading" -description "$description" &
        jamfHelperPID=$!
    else
        /bin/echo "Launching jamfHelper as Utility Window..."
        /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -icon "$icon" -heading "$heading" -description "$description" -iconSize 100 &
        jamfHelperPID=$!
    fi
    ##Load LaunchAgent
    if [[ ${fvStatus} == "FileVault is On." ]] && [[ ${currentUser} != "root" ]]; then
        userID=$( /usr/bin/id -u "${currentUser}" )
        /bin/launchctl bootstrap gui/"${userID}" /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist
    fi
    ##Begin Upgrade
    /bin/echo "Launching startosinstall..."
    ##Check if eraseInstall is Enabled
    if [[ $eraseInstall == 1 ]]; then
        eraseopt='--eraseinstall'
        /bin/echo "   Script is configured for Erase and Install of macOS."
    fi

    osinstallLogfile="/var/log/startosinstall.log"
    if [ "$versionMajor" -ge 14 ]; then
        eval sudo nohup ""$OSInstaller/Contents/Resources/startosinstall"" "$eraseopt" --agreetolicense --nointeraction --pidtosignal "$jamfHelperPID" >> "$osinstallLogfile" &
    else
        eval /usr/bin/nohup ""$OSInstaller/Contents/Resources/startosinstall"" "$eraseopt" --applicationpath ""$OSInstaller"" --agreetolicense --nointeraction --pidtosignal "$jamfHelperPID" >> "$osinstallLogfile" &
    fi
    /bin/sleep 3
else
    ## Remove Script
    /bin/rm -f /usr/local/jamfps/finishOSInstall.sh
    /bin/rm -f /Library/LaunchDaemons/com.jamfps.cleanupOSInstall.plist
    /bin/rm -f /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist

    /bin/echo "Launching jamfHelper Dialog (Requirements Not Met)..."
    /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -icon "$icon" -heading "Requirements Not Met" -description "We were unable to prepare your computer for $macOSname. Please ensure you are connected to power and that you have at least 15GB of Free Space.

    If you continue to experience this issue, please contact the IT Support Center." -iconSize 100 -button1 "OK" -defaultButton 1

fi

cleanExit 0

If you notice any errors or have recommendations how to do things differently please let me know.

jlang_remedy
New Contributor III

Thanks. @hpavlic. I edited this to revert back to the original power check, and ran this on a test machine currently on 10.12.6 and for some reason the machine still got stuck on the pre-upgrade splash screen. I have mine running as a utility window I opened User's and groups in sys prefs and did in fact see the current user was promoted to admin, but the upgrade just won't start. I didn not get prompted for OSinstallersetupd as before though which is good. JSS logs show the below and the log file in the script for the install is showing empty when I open it.

[STEP 1 of 4]
Executing Policy Install MacOS Mojave
[STEP 2 of 4]
Running script 10.14.1...
Script exit code: 0
Script result: User is not an Admin. Adding atest to Admin group
Demote token file added for atest at /Users/atest/.demoteafterupgrade
Power Check: OK - AC Power Detected
Launching jamfHelper as Utility Window...
/Library/LaunchAgents/com.apple.install.osinstallersetupd.plist: service already loaded
Launching startosinstall...
[STEP 3 of 4]
[STEP 4 of 4]

Perhaps I need to try another machine maybe 10.13.x and see if I get any better results with this.

hpavlic_
New Contributor III

@jlang_remedy

Can you please check what does it say in the startosinstall log, located under /var/log/startosinstall.log?

From that we can get more information

deej
New Contributor III

Here's what I'm doing to avoid the "osinstallersetupd wants to make changes" issue:

Prior to invoking startosinstall:

## Elevation to avoid osinstallersetupd issue.
/usr/sbin/dseditgroup -q -o create -n /Local/Default -r "Admin access for macOS upgrade" upgradeadmin
/usr/sbin/dseditgroup -q -o edit -n /Local/Default -a upgradeadmin -t group admin
/usr/sbin/dseditgroup -o edit -a "${currentUser}" -t user upgradeadmin
/usr/bin/dsmemberutil flushcache

Added to the finishOSinstall.sh:

/usr/sbin/dseditgroup -o delete -n /Local/Default upgradeadmin
/usr/bin/dsmemberutil flushcache

If they were already a member of the admin group, that will remain unchanged. If they weren't, they got elevated through a temporary nested group, and the finish script can delete that group without worrying about who is logged in or any pre-existing membership.

In my case, users on staff machines already have admin access, so the upgrade from 10.13 and below would go smoothly. I noticed this during 10.14-to-10.14 "upgrade"/refresh installs, because as part of our Cybersecurity program, we're stripping off default admin access, to be replaced by targeted authorizationdb access to certain functionality. I still expect to need to accommodate the possibility of an admin exception (approved by our Cyber team).

glaske
New Contributor III

We have noticed that if we push the macOS Mojave installer via VPP to the machine, they get a notification to restart and install the OS automatically. This is also true when placed in Self Service. Might be worth a try for you all as it doesn't require any work on your end. Only was able to confirm that the user receives this message if on 10.13 and 10.14 so far.

568b859c675d49a9903184477715c163

Cheers,
Chris

hpavlic_
New Contributor III

@deej

Great idea, this is an excellent solution! It removes the need to put a dummy file and works for all users.

Placed it into my script and it is working as expected.

Thank you :)

jlang_remedy
New Contributor III

@hpavlic. the /var/log/starttoinstall.log file is empty so I can't seem to pin-point what's causing the hang as yet.

Also, can you or @deej post the full version of the script which includes @deej's latest edit to solve the admin issue.

Just want to be doubly sure all the bits that need to be removed/added are done in the right place in the script to avoid any inadvertent issues.

danshaw
Contributor II

For those who have been able to upgrade from 10.12 & 10.13 to 10.14 successfully, I am hoping you can help me identify why it's still not working for me. What makes it hard is that I don't know where it is failing in the install process.

  • The installer downloads and installs fine.
  • The process gets somewhere hung up at the startosinstall.
  • The startosinstall.log is empty.

Any ideas what might be causing the upgrade issue? Some users are saying that the computer reboots and then looks to install, but when they log back in, it hasn't been upgraded.

All our computers are encrypted via FileVault if that matters.

Here is the JAMF log from a failed upgrade. This user was on 10.12.6

59148f466a0c4ff2916d5127d4ab09f0

And here is the section of the script that I think its getting hung up on, but its just a guess:

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# APPLICATION
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

if [[ ${pwrStatus} == "OK" ]] && [[ ${spaceStatus} == "OK" ]]; then
    ##Launch jamfHelper
    if [ ${userDialog} -eq 0 ]; then
        /bin/echo "Launching jamfHelper as FullScreen..."
        /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -title "" -icon "$icon" -heading "$heading" -description "$description" &
        jamfHelperPID=$!
    else
        /bin/echo "Launching jamfHelper as Utility Window..."
        /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -icon "$icon" -heading "$heading" -description "$description" -iconSize 100 &
        jamfHelperPID=$!
    fi
    ##Load LaunchAgent
    if [[ ${fvStatus} == "FileVault is On." ]] && [[ ${currentUser} != "root" ]]; then
        userID=$( /usr/bin/id -u "${currentUser}" )
        /bin/launchctl bootstrap gui/"${userID}" /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist
    fi
    ##Begin Upgrade
    /bin/echo "Launching startosinstall..."
    consoleUser=`ls -l /dev/console | cut -d " " -f4`
    effectiveUserID=$(/usr/bin/id -u "$consoleUser")
    /bin/launchctl asuser "$effectiveUserID" sudo -u "$consoleUser" /usr/bin/open /Applications/Install macOS Mojave.app
    sleep 5
    /bin/launchctl asuser "$effectiveUserID" sudo -u "$consoleUser" osascript -e 'quit app "Install macOS Mojave"'
    /Applications/Install macOS Mojave.app/Contents/Resources/startosinstall --applicationpath "/Applications/Install macOS Mojave.app" --nointeraction --pidtosignal $jamfHelperPID &
    /bin/sleep 3
    ##Check if eraseInstall is Enabled
    if [[ $eraseInstall == 1 ]]; then
        eraseopt='--eraseinstall'
        /bin/echo "   Script is configured for Erase and Install of macOS."
    fi

    osinstallLogfile="/var/log/startosinstall.log"
    if [ "$versionMajor" -ge 14 ]; then
        eval /usr/bin/nohup ""$OSInstaller/Contents/Resources/startosinstall"" "$eraseopt" --agreetolicense --nointeraction --pidtosignal "$jamfHelperPID" >> "$osinstallLogfile" &
    else
        eval /usr/bin/nohup ""$OSInstaller/Contents/Resources/startosinstall"" "$eraseopt" --applicationpath ""$OSInstaller"" --agreetolicense --nointeraction --pidtosignal "$jamfHelperPID" >> "$osinstallLogfile" &
    fi
    /bin/sleep 3
else
    ## Remove Script
    /bin/rm -f /usr/local/jamfps/finishOSInstall.sh
    /bin/rm -f /Library/LaunchDaemons/com.jamfps.cleanupOSInstall.plist
    /bin/rm -f /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist

    /bin/echo "Launching jamfHelper Dialog (Requirements Not Met)..."
    /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -icon "$icon" -heading "Requirements Not Met" -description "We were unable to prepare your computer for $macOSname. Please ensure you are connected to power and that you have at least 15GB of Free Space.

    If you continue to experience this issue, please contact the IT Support Center." -iconSize 100 -button1 "OK" -defaultButton 1

fi

cleanExit 0

hpavlic_
New Contributor III

@danshaw

Im guessing that this is the culprit, you have ##Begin Upgrade part where it tries to launch Mojave

/Applications/Install macOS Mojave.app/Contents/Resources/startosinstall --applicationpath "/Applications/Install macOS Mojave.app" --nointeraction --pidtosignal $jamfHelperPID &

And "--applicationpath" portion is not viable with Mojave.

This part after ##Begin Upgrade is not necessary in the script since the install is executed later:

    consoleUser=`ls -l /dev/console | cut -d " " -f4`
    effectiveUserID=$(/usr/bin/id -u "$consoleUser")
    /bin/launchctl asuser "$effectiveUserID" sudo -u "$consoleUser" /usr/bin/open /Applications/Install macOS Mojave.app
    sleep 5
    /bin/launchctl asuser "$effectiveUserID" sudo -u "$consoleUser" osascript -e 'quit app "Install macOS Mojave"'
    /Applications/Install macOS Mojave.app/Contents/Resources/startosinstall --applicationpath "/Applications/Install macOS Mojave.app" --nointeraction --pidtosignal $jamfHelperPID &
    /bin/sleep 3

@jlang_remedy

Could you check the /var/log/install.log or policy log on the Jamf Console?
Here is the script, hope it helps:

#!/bin/bash

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Copyright (c) 2018 Jamf.  All rights reserved.
#
#       Redistribution and use in source and binary forms, with or without
#       modification, are permitted provided that the following conditions are met:
#               * Redistributions of source code must retain the above copyright
#                 notice, this list of conditions and the following disclaimer.
#               * Redistributions in binary form must reproduce the above copyright
#                 notice, this list of conditions and the following disclaimer in the
#                 documentation and/or other materials provided with the distribution.
#               * Neither the name of the Jamf nor the names of its contributors may be
#                 used to endorse or promote products derived from this software without
#                 specific prior written permission.
#
#       THIS SOFTWARE IS PROVIDED BY JAMF SOFTWARE, LLC "AS IS" AND ANY
#       EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#       WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#       DISCLAIMED. IN NO EVENT SHALL JAMF SOFTWARE, LLC BE LIABLE FOR ANY
#       DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
#       (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
#       LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#       ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#       (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#       SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# This script was designed to be used in a Self Service policy to ensure specific
# requirements have been met before proceeding with an inplace upgrade of the macOS,
# as well as to address changes Apple has made to the ability to complete macOS upgrades
# silently.
#
# VERSION: v2.7.2.1
#
# REQUIREMENTS:
#           - Jamf Pro
#           - macOS Clients running version 10.10.5 or later
#           - macOS Installer 10.12.4 or later
#           - eraseInstall option is ONLY supported with macOS Installer 10.13.4+ and client-side macOS 10.13+
#           - Look over the USER VARIABLES and configure as needed.
#
#
# For more information, visit https://github.com/kc9wwh/macOSUpgrade
#
#
# Written by: Joshua Roskos | Jamf
#
# Created On: January 5th, 2017
# Updated On: September 28th, 2018
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# USER VARIABLES
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

##Specify path to OS installer. Use Parameter 4 in the JSS, or specify here
##Example: /Applications/Install macOS High Sierra.app
OSInstaller="$4"

##Version of Installer OS. Use Parameter 5 in the JSS, or specify here.
##Example Command: /usr/libexec/PlistBuddy -c 'Print :"System Image Info":version' "/Applications/Install macOS High Sierra.app/Contents/SharedSupport/InstallInfo.plistr"
##Example: 10.12.5
version="$5"
versionMajor=$( /bin/echo "$version" | /usr/bin/awk -F. '{print $2}' )
versionMinor=$( /bin/echo "$version" | /usr/bin/awk -F. '{print $3}' )

##Custom Trigger used for download. Use Parameter 6 in the JSS, or specify here.
##This should match a custom trigger for a policy that contains just the 
##MacOS installer. Make sure that the policy is scoped properly
##to relevant computers and/or users, or else the custom trigger will
##not be picked up. Use a separate policy for the script itself.
##Example trigger name: download-sierra-install
download_trigger="$6"

##MD5 Checksum of InstallESD.dmg
##This variable is OPTIONAL
##Leave the variable BLANK if you do NOT want to verify the checksum (DEFAULT)
##Example Command: /sbin/md5 /Applications/Install macOS High Sierra.app/Contents/SharedSupport/InstallESD.dmg
##Example MD5 Checksum: b15b9db3a90f9ae8a9df0f81741efa2b
installESDChecksum="$7"

##Valid Checksum?  O (Default) for false, 1 for true.
validChecksum=0

##Unsuccessful Download?  0 (Default) for false, 1 for true.
unsuccessfulDownload=0

##Erase & Install macOS (Factory Defaults)
##Requires macOS Installer 10.13.4 or later
##Disabled by default
##Options: 0 = Disabled / 1 = Enabled
##Use Parameter 8 in the JSS.
eraseInstall="$8"
if [[ "${eraseInstall:=0}" != 1 ]]; then eraseInstall=0 ; fi
#macOS Installer 10.13.3 or ealier set 0 to it.
if [ "$versionMajor${versionMinor:=0}" -lt 134 ]; then
    eraseInstall=0
fi

##Enter 0 for Full Screen, 1 for Utility window (screenshots available on GitHub)
##Full Screen by default
##Use Parameter 9 in the JSS.
userDialog="$9"
if [[ ${userDialog:=0} != 1 ]]; then userDialog=0 ; fi

##Title of OS
##Example: macOS High Sierra
macOSname=$(/bin/echo "$OSInstaller" | /usr/bin/sed 's/^/Applications/Install (.*).app$/1/')

##Title to be used for userDialog (only applies to Utility Window)
title="$macOSname Upgrade"

##Heading to be used for userDialog
heading="Please wait as we prepare your computer for $macOSname..."

##Title to be used for userDialog
description="This process will take approximately 5-10 minutes.
Once completed your computer will reboot and begin the upgrade."

##Description to be used prior to downloading the OS installer
dldescription="We need to download $macOSname to your computer, this will 
take several minutes."

##Jamf Helper HUD Position if macOS Installer needs to be downloaded
##Options: ul (Upper Left); ll (Lower Left); ur (Upper Right); lr (Lower Right)
##Leave this variable empty for HUD to be centered on main screen
dlPosition="ul"

##Icon to be used for userDialog
##Default is macOS Installer logo which is included in the staged installer package
icon="$OSInstaller/Contents/Resources/InstallAssistant.icns"

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# FUNCTIONS
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

downloadInstaller() {
    /bin/echo "Downloading macOS Installer..."
    /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper 
        -windowType hud -windowPosition $dlPosition -title "$title" -alignHeading center -alignDescription left -description "$dldescription" 
        -lockHUD -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/SidebarDownloadsFolder.icns" -iconSize 100 &
    ##Capture PID for Jamf Helper HUD
    jamfHUDPID=$!
    ##Run policy to cache installer
    /usr/local/jamf/bin/jamf policy -event "$download_trigger"
    ##Kill Jamf Helper HUD post download
    /bin/kill "${jamfHUDPID}"
}

verifyChecksum() {
    if [[ "$installESDChecksum" != "" ]]; then
        osChecksum=$( /sbin/md5 -q "$OSInstaller/Contents/SharedSupport/InstallESD.dmg" )
        if [[ "$osChecksum" == "$installESDChecksum" ]]; then
            /bin/echo "Checksum: Valid"
            validChecksum=1
            return
        else
            /bin/echo "Checksum: Not Valid"
            /bin/echo "Beginning new dowload of installer"
            /bin/rm -rf "$OSInstaller"
            /bin/sleep 2
            downloadInstaller
        fi
    else
        ##Checksum not specified as script argument, assume true
        validChecksum=1
        return
    fi
}

cleanExit() {
    /bin/kill "${caffeinatePID}"
    exit "$1"
}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# SYSTEM CHECKS
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

##Caffeinate
/usr/bin/caffeinate -dis &
caffeinatePID=$!

##Get Current User
currentUser=$( /usr/bin/stat -f %Su /dev/console )

##Get Current Users homefolder
currentUserHomeDirectory=$( /usr/bin/dscl . -read "/users/$currentUser" NFSHomeDirectory | cut -d " " -f 2 )

## Elevation to avoid osinstallersetupd issue.
/usr/sbin/dseditgroup -q -o create -n /Local/Default -r "Admin access for macOS upgrade" upgradeadmin
/usr/sbin/dseditgroup -q -o edit -n /Local/Default -a upgradeadmin -t group admin
/usr/sbin/dseditgroup -o edit -a "${currentUser}" -t user upgradeadmin
/usr/bin/dsmemberutil flushcache

##Check if FileVault Enabled
fvStatus=$( /usr/bin/fdesetup status | head -1 )

## Check if battery is below 80%
battLevel=$( pmset -g ps  |  sed -n 's/.*[[:blank:]]+*(.*%).*/1/p' )
if [[ ${battLevel} > *"80"* ]]; then
    pwrStatus="OK"
    /bin/echo "Power Check: OK - Battery above 80%"
else
    #pwrStatus="ERROR"
     pwrStatus="OK"
    /bin/echo "Power Check: ERROR - Battery level below 80%"
fi


##Check if free space > 10GB
osMajor=$( /usr/bin/sw_vers -productVersion | /usr/bin/awk -F. '{print $2}' )
osMinor=$( /usr/bin/sw_vers -productVersion | /usr/bin/awk -F. '{print $3}' )
if [[ $osMajor -eq 12 ]] || [[ $osMajor -eq 13 && $osMinor -lt 4 ]]; then
    freeSpace=$( /usr/sbin/diskutil info / | /usr/bin/grep "Available Space" | /usr/bin/awk '{print $6}' | /usr/bin/cut -c 2- )
else
    freeSpace=$( /usr/sbin/diskutil info / | /usr/bin/grep "Free Space" | /usr/bin/awk '{print $6}' | /usr/bin/cut -c 2- )
fi

if [[ ${freeSpace%.*} -ge 10000000000 ]]; then
    spaceStatus="OK"
    /bin/echo "Disk Check: OK - ${freeSpace%.*} Bytes Free Space Detected"
else
    spaceStatus="ERROR"
    /bin/echo "Disk Check: ERROR - ${freeSpace%.*} Bytes Free Space Detected"
fi

##Check for existing OS installer
loopCount=0
while [[ $loopCount -lt 3 ]]; do
    if [ -e "$OSInstaller" ]; then
        /bin/echo "$OSInstaller found, checking version."
        OSVersion=$(/usr/libexec/PlistBuddy -c 'Print :"System Image Info":version' "$OSInstaller/Contents/SharedSupport/InstallInfo.plist")
        /bin/echo "OSVersion is $OSVersion"
        if [ "$OSVersion" = "$version" ]; then
          /bin/echo "Installer found, version matches. Verifying checksum..."
          verifyChecksum
        else
          ##Delete old version.
          /bin/echo "Installer found, but old. Deleting..."
          /bin/rm -rf "$OSInstaller"
          /bin/sleep 2
          downloadInstaller
        fi
        if [ "$validChecksum" == 1 ]; then
            unsuccessfulDownload=0
            break
        fi
    else
        downloadInstaller
    fi

    unsuccessfulDownload=1
    ((loopCount++))
done

if (( unsuccessfulDownload == 1 )); then
    /bin/echo "macOS Installer Downloaded 3 Times - Checksum is Not Valid"
    /bin/echo "Prompting user for error and exiting..."
    /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -icon "$icon" -heading "Error Downloading $macOSname" -description "We were unable to prepare your computer for $macOSname. Please contact the IT Support Center." -iconSize 100 -button1 "OK" -defaultButton 1
    cleanExit 0
fi


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

/bin/mkdir -p /usr/local/jamfps

/bin/cat > /usr/local/jamfps/finishOSInstall.sh <<'EOL'
#!/bin/bash

##Demote if user was not an admin before upgrade
/usr/sbin/dseditgroup -o delete -n /Local/Default upgradeadmin
/usr/bin/dsmemberutil flushcache

## First Run Script to remove the installer.
## Clean up files
/bin/rm -fr "$OSInstaller"
/bin/sleep 2

## Update Device Inventory
/usr/local/jamf/bin/jamf recon

## Remove LaunchDaemon
/bin/rm -f /Library/LaunchDaemons/com.jamfps.cleanupOSInstall.plist

## Remove Script
/bin/rm -fr /usr/local/jamfps

exit 0
EOL

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

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

/bin/cat << EOF > /Library/LaunchDaemons/com.jamfps.cleanupOSInstall.plist
<?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.cleanupOSInstall</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>-c</string>
        <string>/usr/local/jamfps/finishOSInstall.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
EOF

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

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# LAUNCH AGENT FOR FILEVAULT AUTHENTICATED REBOOTS
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

##Determine Program Argument
if [[ $osMajor -ge 11 ]]; then
    progArgument="osinstallersetupd"
elif [[ $osMajor -eq 10 ]]; then
    progArgument="osinstallersetupplaind"
fi

/bin/cat << EOP > /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist
<?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.apple.install.osinstallersetupd</string>
    <key>LimitLoadToSessionType</key>
    <string>Aqua</string>
    <key>MachServices</key>
    <dict>
        <key>com.apple.install.osinstallersetupd</key>
        <true/>
    </dict>
    <key>TimeOut</key>
    <integer>300</integer>
    <key>OnDemand</key>
    <true/>
    <key>ProgramArguments</key>
    <array>
        <string>$OSInstaller/Contents/Frameworks/OSInstallerSetup.framework/Resources/$progArgument</string>
    </array>
</dict>
</plist>
EOP

##Set the permission on the file just made.
/usr/sbin/chown root:wheel /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist
/bin/chmod 644 /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# APPLICATION
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

if [[ ${pwrStatus} == "OK" ]] && [[ ${spaceStatus} == "OK" ]]; then
    ##Launch jamfHelper
    if [ ${userDialog} -eq 0 ]; then
        /bin/echo "Launching jamfHelper as FullScreen..."
        /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -title "" -icon "$icon" -heading "$heading" -description "$description" &
        jamfHelperPID=$!
    else
        /bin/echo "Launching jamfHelper as Utility Window..."
        /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -icon "$icon" -heading "$heading" -description "$description" -iconSize 100 &
        jamfHelperPID=$!
    fi
    ##Load LaunchAgent
    if [[ ${fvStatus} == "FileVault is On." ]] && [[ ${currentUser} != "root" ]]; then
        userID=$( /usr/bin/id -u "${currentUser}" )
        /bin/launchctl bootstrap gui/"${userID}" /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist
    fi
    ##Begin Upgrade
    /bin/echo "Launching startosinstall..."
    ##Check if eraseInstall is Enabled
    if [[ $eraseInstall == 1 ]]; then
        eraseopt='--eraseinstall'
        /bin/echo "   Script is configured for Erase and Install of macOS."
    fi

    osinstallLogfile="/var/log/startosinstall.log"
    if [ "$versionMajor" -ge 14 ]; then
        eval /usr/bin/nohup ""$OSInstaller/Contents/Resources/startosinstall"" "$eraseopt" --agreetolicense --nointeraction --pidtosignal "$jamfHelperPID" >> "$osinstallLogfile" &
    else
        eval /usr/bin/nohup ""$OSInstaller/Contents/Resources/startosinstall"" "$eraseopt" --applicationpath ""$OSInstaller"" --agreetolicense --nointeraction --pidtosignal "$jamfHelperPID" >> "$osinstallLogfile" &
    fi
    /bin/sleep 3
else
    ## Remove Script
    /bin/rm -f /usr/local/jamfps/finishOSInstall.sh
    /bin/rm -f /Library/LaunchDaemons/com.jamfps.cleanupOSInstall.plist
    /bin/rm -f /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist

    /bin/echo "Launching jamfHelper Dialog (Requirements Not Met)..."
    /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -icon "$icon" -heading "Requirements Not Met" -description "We were unable to prepare your computer for $macOSname. Please ensure you are connected to power and that you have at least 10GB of Free Space.

    If you continue to experience this issue, please contact the IT Support Center." -iconSize 100 -button1 "OK" -defaultButton 1

fi

cleanExit 0

MTFIDjamf
Contributor II

@hpavlic. Adding that dock piece to the script made it work for me!

The process runs through as designed. When complete my standard user is still a standard user and the device is on Mojave. Thank you for the help!

seann
Contributor

@glaske This looks cool. However the issue with this method is that installers are removed when a new OS is released, after which it won't be available for VPP.

dmitchell
Contributor

Right now I am caching the Mojave installer on Macs. I have a policy in Self Service that appears once the installer is cached. The policy installs the cached installer and then runs a script that starts the Mojave upgrade. I have ran it on about 10 Macs with operating systems ranging from 10.9 to 10.13 and it works great.

danshaw
Contributor II

@hpavlic., thank you for providing the script! Early tests are showing that this is working for me.

I did notice that you have the battery check part of your script commented to pass all the time. Were you finding that it wasn't accurate?

## Check if battery is below 80%
battLevel=$( pmset -g ps  |  sed -n 's/.*[[:blank:]]+*(.*%).*/1/p' )
if [[ ${battLevel} > *"80"* ]]; then
    pwrStatus="OK"
    /bin/echo "Power Check: OK - Battery above 80%"
else
    #pwrStatus="ERROR"
     pwrStatus="OK"
    /bin/echo "Power Check: ERROR - Battery level below 80%"
fi

hpavlic_
New Contributor III

@danshaw

Ohhhhh, sorry about that, it is a mistake!!!
I was testing something on VM and that part fails as it cannot detect battery so I left it out and put pwrStatus=“OK”.
That should be commented out and power status OK removed!

danshaw
Contributor II

I was testing on a VM and noticed the same thing! Good call.

bbot
Contributor

.

jlang_remedy
New Contributor III

@hpavlic. the JSS log looked normal, I think i copied it earlier in this thread. For /var/log/install.log I have to go back and check.
I did end up getting the original test machine to upgrade, FINALLY! but only after 2 or 3 reboots and retrying then it suddenly worked. I think I just need to do more testing but so far with 4 machines, all different model macbooks between 10.126 - 10.13.6 they all hung on the pre-upgrade on first try, then like my first test machine took a few reboots and retries to get it to work.

After a few more test upgrades if this still remains the case, i'll post my edited script to see if something is wrong there, although it wouldn't explain why it eventually works. Here's 2 questions I had though.

  1. I see as part of the finishOSinstall script there's a line to remove the Installer folder.
## Clean up files
/bin/rm -fr "$OSInstaller"
/bin/sleep 2

Doesn't the upgrade do that by default(unfortunately)? I took that line out, hoping to save the installer in the /Applications folder for future Erase and Install's but found it was deleted anyway even though I took that line out?

  1. I found a thread where someone ran startoinstall via command line instead of self service script and the CLI showed a percentage progress bar before the reboot kicks in. a87e4ebad78b460093e7db4e715fcc0b

    It would be totally awesome to have something similar on that black jamfhelper pre-upgrade waiting screen to at least indicate if progress is being made or not. For now, I simply wait 10 - 15 mins max and if the machine hasn't rebooted I assume it's stuck at that point, and I reboot for extra measure and try once more. To avoid running blind during this point, Is it possible to script a different utility window that can show the progress being made, ideally with verbose output to give indication everything is working or the process hasn't errored out and frozen. I think 1 out of 4 tests i tried did show something in /var/log/startosinstall.log which has been usually empty for me. It said Unable to create a preboot APFS volume. Not sure how to prevent such an error but at least that was helpful to know why it stopped in that 1 test scenario.

danshaw
Contributor II

Has anyone been able to figure out a way to block users from upgrading via the app store and force them to upgrade in self service? Our users don't have admin rights so when they try they need admin creds, but using this script that @hpavlic. provided above, its using an admin account to do the upgrade and the process/app is getting blocked by the restriction I put into place.

I tried some fancy work such as laying down a dummy receipt at the beginning of the upgrade, scoping that to a smartgroup that excludes that computer from the restriction and then running sudo jamf manage, but that isn't working very well.

Wondering if anyone else has found a solution in their environments.

01e5f5acc48346738c1ba589c4eb6d28

bpavlov
Honored Contributor

@danshaw InstallAssistant is the process name you'd want to block.

danshaw
Contributor II

Thanks @bpavlov . Looks to be updating now properly. The last piece I am struggling with is how to push down some Kernel Extension Config Policies immediately after the upgrade. Without them, users get popup notifications.

For some reason, my first boot script isn't running any of the policies that I have inserted in there. Doing a recon at that point would probably solve the problem, but that script isn't running.

@steve.summers , you mentioned above to create a smart group (named whatever) and as the criteria, have this:Profile Name Has Privacy Preferences Policy Control. (Last check in less than 15 days and that PPPC setting...that's it)., but doesn't this then install on all computers? How can I prevent this from being installed on all computers not on 10.14 and then push it immediately after?

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

/bin/mkdir -p /usr/local/jamfps

/bin/cat > /usr/local/jamfps/finishOSInstall.sh <<'EOL'
#!/bin/bash

##Demote if user was not an admin before upgrade
/usr/sbin/dseditgroup -o delete -n /Local/Default upgradeadmin
/usr/bin/dsmemberutil flushcache

## First Run Script to remove the installer.
## Clean up files
# /bin/rm -fr "$OSInstaller"
/bin/sleep 2
/usr/local/jamf/bin/jamf policy -event SetDesktop
/bin/sleep 2
/usr/local/jamf/bin/jamf recon
/bin/sleep 2
## Running manage
/usr/local/jamf/bin/jamf manage
sleep 2
## Remove LaunchDaemon
/bin/rm -f /Library/LaunchDaemons/com.jamfps.cleanupOSInstall.plist

## Remove Script
/bin/rm -fr /usr/local/jamfps
exit 0
EOL
/usr/sbin/chown root:admin /usr/local/jamfps/finishOSInstall.sh
/bin/chmod 755 /usr/local/jamfps/finishOSInstall.sh

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

/bin/cat << EOF > /Library/LaunchDaemons/com.jamfps.cleanupOSInstall.plist
<?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.cleanupOSInstall</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>-c</string>
        <string>/usr/local/jamfps/finishOSInstall.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
EOF

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

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# LAUNCH AGENT FOR FILEVAULT AUTHENTICATED REBOOTS
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

##Determine Program Argument
if [[ $osMajor -ge 11 ]]; then
    progArgument="osinstallersetupd"
elif [[ $osMajor -eq 10 ]]; then
    progArgument="osinstallersetupplaind"
fi

/bin/cat << EOP > /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist
<?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.apple.install.osinstallersetupd</string>
    <key>LimitLoadToSessionType</key>
    <string>Aqua</string>
    <key>MachServices</key>
    <dict>
        <key>com.apple.install.osinstallersetupd</key>
        <true/>
    </dict>
    <key>TimeOut</key>
    <integer>300</integer>
    <key>OnDemand</key>
    <true/>
    <key>ProgramArguments</key>
    <array>
        <string>$OSInstaller/Contents/Frameworks/OSInstallerSetup.framework/Resources/$progArgument</string>
    </array>
</dict>
</plist>
EOP

##Set the permission on the file just made.
/usr/sbin/chown root:wheel /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist
/bin/chmod 644 /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist

szultzie
Contributor II

@danshaw We use the Restricted Software and it seem to work pretty good.

You need two from what I can gather.

69b59e55ef60449a985e7119da8a8f22
f6a2bdc81add40be85133d070c183da6

I also use this to hide 10.14.x releases

405cccf8faf64c0796db333da040a33c

So far it has been working for us, Starting with High Sierra last year.

-Peter

achristoforatos
Contributor II

What do you guys put as the trigger to have these mojave install scripts run once? I'm new to this and was looking for help.