macOS Self Service Upgrade Process

fedagain
Contributor

Hi all, looking for some assistance with getting this....

https://github.com/kc9wwh/macOSUpgrade

working correctly. I "think" I've done all that is really required, but no go! I have the parameters set and a separate policy for the OS (Mojave) installer and is called in a parameter in the script policy.

I want to use it as a clean install, and have that set in the parameters also. The execution doesn't seem to do much of anything, no install of the OS installer, no splash screen, nothing, and the log hasn't been much help either. Typically don't have any issues with getting this stuff to work.

Any hints, advice on where to look would be appreciated!

19 REPLIES 19

mm2270
Legendary Contributor II

Maybe you could post a little more detail on how you've set it up, like a few screenshots and such. I've used the script before and have found it to work well, so I'm not really sure where the problem might be without seeing a little more of your particular setup.

One thing to note. The scripts eraseInstall option makes use of a command that only works on High Sierra APFS formatted disks, which means 10.13.4 or higher. You don't happen to be trying to use this on machines still running Sierra or an earlier release of High Sierra by any chance are you?

fedagain
Contributor

My testing is on 10.14.4 machines.

I have attached screenshots for the two policies. Both policies are scoped the same!

cc06d6eddc174b2ab24d68d93024e220
a9b0026984c54e65b679f099ac42dc79

84825c3328d24879899db89efd6be5a1
cde3954e5430476fbe144796c5da7905

mm2270
Legendary Contributor II

Ok, first glance, that all looks to be in order. Is the Install macOS Mojave.app you're using already predownloaded to the machine when you run this, or are you relying on the mojaveinstaller custom triggered policy to download it at run time? If you're doing the latter, I would try pre-downloading it to see if it makes any difference.

Other than that, I'm not sure yet what to tell you. It should be working I think.

fedagain
Contributor

@mm2270

I have tried it both ways with the same result. SMH on this one. Any MODS that NEED to be made to the script (domain, etc etc..)? I haven't modded the script at all since I put all the variables in the parameters section.

mm2270
Legendary Contributor II

No, no mods should be needed. I personally made my own modifications to the script when I used it, but only because I wanted to add some additional functionality to it. As is the script should work.

As a test, can you try running the command that the script will run on a machine with Mojave installer in the Applications folder? Like

sudo /Applications/Install macOS Mojave.app/Contents/Resources/startosinstall --eraseinstall --nointeraction --agreetolicense

and see if it works? If it does then we know the installer is doing what it's supposed to.

This actually might be a good time to mention that using the --eraseinstall flag in that command causes a bit of a delay. The reason is, and you'll see this if you run it directly in the Terminal, is that it actually creates an additional partition, and copies files into it before the Mac reboots. It's usually not more than about a minute or so, but it's definitely not immediate in case that's what you were expecting. I'm assuming you allowed the Self Service policy to run for a bit before concluding that it wasn't working, but I just wanted to be sure that the delay was clear. I took your original post to mean that even the jamfHelper message wasn't popping up, but I'm not entirely clear.

sdagley
Honored Contributor II

@fedagain In your screen shot of MacOSCleanInstall settings there's no trigger specified for the policy. Are you trying to run it from Self Service?

fedagain
Contributor

@sdagley

I've run that policy both by CLI (calling it by -id) and SS. The MacOSCleanInstall policy is an SS policy and is set to ongoing, so that should be fine for that part.

fedagain
Contributor

@mm2270

Yes, calling the installer via that command works.

fedagain
Contributor

@sdagley
@mm2270

Found the issue... the name of my script had a / in the title.... for some reason that broke the whole thing!

landon_Starr
Contributor

This should help explain things in a bit more detail :)

https://hcsonline.com/support/white-papers/use-jamf-self-service-to-upgrade-to-macos-mojave

sdagley
Honored Contributor II

@fedagain Thanks for the update, that's a good one to know. Along the same lines I discovered today that you can't use a ! in the password for a distribution point. That problem has become a PI so it'll (hopefully) get fixed at some point in the future. You might share your discovery of the / issue in script names with your technical contact to see if a PI will be created for it.

mm2270
Legendary Contributor II

It makes sense you can’t use a forward slash in a script name. It might apply to other items as well, like packages. It would be seen as a path delimiter (I guess).

The strange thing to me is that Jamf Pro even allows you to name it that way without a warning. If the product isn’t going to support slashes in names, then the least it can do is warn you not to do that.

monaronyc
Contributor

Followed everything to the T with the c9wwh /macOSUpgrade script (Thanks for this!) but one problem. And we've noticed this mostly on the Sierra machines we are trying to upgrade to Mojave. Right when its about to restart to install, we get this:

76fce7ad85904102809659b5cfcaf5f5

Anyone else seen this?

AVmcclint
Honored Contributor

@monaronyc I'm seeing it with Macs being upgraded from Mojave to Catalina. Clicking Try Again 3 times seems to be enough to quit Self Service and begin with the reboot.

jbisgett
Contributor II

@monaronyc this is an open item on the GitHub page for this script, one workaround is to add

killall Self Service

right before

##Load LaunchAgent

on line 491

niacobelli
New Contributor III

Hi all,
I'm trying to get this working with upgrading to Catalina. On my test machine, it keeps trying to download the installer even though it is already installed in the Applications folder. Any ideas what I'm over looking?

mm2270
Legendary Contributor II

@niacobelli Are you passing the path to the full installer to the script in parameter 4? Or is it hardcoded on the line where OSInstaller is referenced in the script? If you don't have either of those items in place, the script may think it needs to download the full installer instead of looking on disk for it.

niacobelli
New Contributor III

@mm2270 I do not have it hardcoded in the script, but it is passed using the variable in the policy. I just copied and pasted the Jamf script from github. I used this last year with a Mojave installer without issue. Just trying to figure out what I'm missing.

#!/bin/bash

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Copyright (c) 2019 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.
#
# 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
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# APS Updates added 11/28/2019
#
# Updated "validate_free_space" to work with Catalina – freeSpace
# Added "Print :APFSContainerFree"
# /usr/libexec/PlistBuddy -c "Print :APFSContainerFree" /dev/stdin <<< "$diskInfoPlist" 2>/dev/null || /usr/libexec/PlistBuddy -c "Print :FreeSpace" /dev/stdin <<< "$diskInfoPlist" 2>/dev/null || /usr/libexec/PlistBuddy -c "Print :AvailableSpace" /dev/stdin <<< "$diskInfoPlist" 2>/dev/null
# 
# Updated loopCout to work with Stub/Lite installer – Stub/Lite installer does not specify a macOS version.
# Check to see if the installer version matches, or if the installer does not have InstallInfo.plist.
# if [ "$currentInstallerVersion" = "$installerVersion" ] || [[ ! -e "$OSInstaller/Contents/SharedSupport/InstallInfo.plist" ]]; then
#
# Updated variable "currentUser"
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

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

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

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

## Custom Trigger used for download – Use Parameter 6 in the JSS, or specify here.
## Parameter Label: Download Policy Trigger
## 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 – Use Parameter 7 in the JSS.
## Parameter Label: installESD Checksum (optional)
## 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.
## Parameter Label: Upgrade or Erase (0 or 1)
eraseInstall="$8"
if [ "$eraseInstall" != "1" ]; then eraseInstall=0 ; fi
# macOS Installer 10.13.3 or ealier set 0 to it.
if [ "$installerVersionMajor${installerVersionMinor:=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.
## Parameter Label: Full Screen or Dialog Box (0 or 1)
userDialog="$9"
if [ "$userDialog" != "1" ]; then userDialog=0 ; fi

# Control for auth reboot execution.
if [ "$installerVersionMajor" -ge 14 ]; then
    # Installer of macOS 10.14 or later set cancel to auth reboot.
    cancelFVAuthReboot=1
else
    # Installer of macOS 10.13 or earlier try to do auth reboot.
    cancelFVAuthReboot=0
fi

## Title of OS
macOSname=$(/bin/echo "$OSInstaller" | /usr/bin/sed -E 's/(.+)?Install(.+).app/?/2/' | /usr/bin/xargs)

## 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="Your computer will reboot in 5-10 minutes and begin the upgrade.
This process will take approximately 30-40 minutes."

## 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"

## First run script to remove the installers after run installer
finishOSInstallScriptFilePath="/usr/local/jamfps/finishOSInstall.sh"

## Launch deamon settings for first run script to remove the installers after run installer
osinstallersetupdDaemonSettingsFilePath="/Library/LaunchDaemons/com.jamfps.cleanupOSInstall.plist"

## Launch agent settings for filevault authenticated reboots
osinstallersetupdAgentSettingsFilePath="/Library/LaunchAgents/com.apple.install.osinstallersetupd.plist"

## Amount of time (in seconds) to allow a user to connect to AC power before moving on
## If null or 0, then the user will not have the opportunity to connect to AC power
acPowerWaitTimer="0"

## Declare the sysRequirementErrors array
declare -a sysRequirementErrors=()

## Icon to display during the AC Power warning
warnIcon="/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/AlertCautionIcon.icns"

## Icon to display when errors are found
errorIcon="/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/AlertStopIcon.icns"

## The startossinstall log file path
osinstallLogfile="/var/log/startosinstall.log"

## caffeinatePID
caffeinatePID=""

## The startossinstall command option array
declare -a startosinstallOptions=()

## Determine binary name
binaryNameForOSInstallerSetup=$([ "$installerVersionMajor" -ge 11 ] && /bin/echo "osinstallersetupd" || /bin/echo "osinstallersetupplaind")

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

kill_process() {
    processPID="$1"
    if /bin/ps -p "$processPID" > /dev/null ; then
        /bin/kill "$processPID"
        wait "$processPID" 2>/dev/null
    fi
}

wait_for_ac_power() {
    local jamfHelperPowerPID
    jamfHelperPowerPID="$1"
    ## Loop for "acPowerWaitTimer" seconds until either AC Power is detected or the timer is up
    /bin/echo "Waiting for AC power..."
    while [[ "$acPowerWaitTimer" -gt "0" ]]; do
        if /usr/bin/pmset -g ps | /usr/bin/grep "AC Power" > /dev/null ; then
            /bin/echo "Power Check: OK - AC Power Detected"
            kill_process "$jamfHelperPowerPID"
            return
        fi
        sleep 1
        ((acPowerWaitTimer--))
    done
    kill_process "$jamfHelperPowerPID"
    sysRequirementErrors+=("Is connected to AC power")
    /bin/echo "Power Check: ERROR - No AC Power Detected"
}

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
    kill_process "$jamfHUDPID"
}

validate_power_status() {
    ## Check if device is on battery or ac power
    ## If not, and our acPowerWaitTimer is above 1, allow user to connect to power for specified time period
    if /usr/bin/pmset -g ps | /usr/bin/grep "AC Power" > /dev/null ; then
        /bin/echo "Power Check: OK - AC Power Detected"
    else
        if [[ "$acPowerWaitTimer" -gt 0 ]]; then
            /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "Waiting for AC Power Connection" -icon "$warnIcon" -description "Please connect your computer to power using an AC power adapter. This process will continue once AC power is detected." &
            wait_for_ac_power "$!"
        else
            sysRequirementErrors+=("Is connected to AC power")
            /bin/echo "Power Check: ERROR - No AC Power Detected"
        fi
    fi
}

validate_free_space() {
    local installerMajor diskInfoPlist freeSpace requiredDiskSpaceSizeGB installerPath installerSizeBytes

    installerMajor="$1"
    installerPath="$2"

    diskInfoPlist=$(/usr/sbin/diskutil info -plist /)
    ## 10.13.4 or later, diskutil info command output changes key from 'AvailableSpace' to 'Free Space' about disk space.
    ## 10.15.0 or later, diskutil info command output changes key from 'APFSContainerFree' to 'Free Space' about disk space.
    freeSpace=$(
    /usr/libexec/PlistBuddy -c "Print :APFSContainerFree" /dev/stdin <<< "$diskInfoPlist" 2>/dev/null || /usr/libexec/PlistBuddy -c "Print :FreeSpace" /dev/stdin <<< "$diskInfoPlist" 2>/dev/null || /usr/libexec/PlistBuddy -c "Print :AvailableSpace" /dev/stdin <<< "$diskInfoPlist" 2>/dev/null
    )

    ## The free space calculation also includes the installer, so it is excluded.
    if [ -e "$installerPath" ]; then
        installerSizeBytes=$(/usr/bin/du -s "$installerPath" | /usr/bin/awk '{print $1}' | /usr/bin/xargs)
        freeSpace=$((freeSpace + installerSizeBytes))
    fi

    ## Check if free space > 15GB (install 10.13) or 20GB (install 10.14+)
    requiredDiskSpaceSizeGB=$([ "$installerMajor" -ge 14 ] && /bin/echo "20" || /bin/echo "15")
    if [[ ${freeSpace%.*} -ge $(( requiredDiskSpaceSizeGB * 1000 * 1000 * 1000 )) ]]; then
        /bin/echo "Disk Check: OK - ${freeSpace%.*} Bytes Free Space Detected"
    else
        sysRequirementErrors+=("Has at least ${requiredDiskSpaceSizeGB}GB of Free Space")
        /bin/echo "Disk Check: ERROR - ${freeSpace%.*} Bytes Free Space Detected"
    fi
}

verifyChecksum() {
    if [ -n "$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 download 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() {
    if [ -n "$caffeinatePID" ]; then
      kill_process "$caffeinatePID"
    fi
    ## Remove Script
    /bin/rm -f "$finishOSInstallScriptFilePath"
    /bin/rm -f "$osinstallersetupdDaemonSettingsFilePath"
    /bin/rm -f "$osinstallersetupdAgentSettingsFilePath"
    exit "$1"
}

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

## If previous processes remain for some reason, the installation will freeze, so kill it.
killingProcesses=("caffeinate" "startosinstall" "$binaryNameForOSInstallerSetup")
for processName in "${killingProcesses[@]}"; do
    [ -z "$processName" ] && continue
    /bin/echo "Killing $processName processes."
    /usr/bin/killall "$processName" 2>&1 || true
done

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

##Get Current User
currentUser=$(/bin/echo 'show State:/Users/ConsoleUser' | /usr/sbin/scutil | /usr/bin/awk '/Name / { print $3 }')

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

## Run system requirement checks
validate_power_status
validate_free_space "$installerVersionMajor" "$OSInstaller"

## Don't waste the users time, exit here if system requirements are not met
if [[ "${#sysRequirementErrors[@]}" -ge 1 ]]; then
    /bin/echo "Launching jamfHelper Dialog (Requirements Not Met)..."
    /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -icon "$errorIcon" -heading "Requirements Not Met" -description "We were unable to prepare your computer for $macOSname. Please ensure your computer meets the following requirements:

$( /usr/bin/printf '	• %s
' "${sysRequirementErrors[@]}" )

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

    cleanExit 1
fi

## Check for existing OS installer
loopCount=0
while [ "$loopCount" -lt 3 ]; do
    if [ -e "$OSInstaller" ]; then
        /bin/echo "$OSInstaller found, checking version."
        currentInstallerVersion=$(/usr/libexec/PlistBuddy -c 'Print :"System Image Info":version' "$OSInstaller/Contents/SharedSupport/InstallInfo.plist")
        /bin/echo "Found macOS installer for version $currentInstallerVersion."
        ## Check to see if the installer version matches, or if the installer does not have InstallInfo.plist.
        if [ "$currentInstallerVersion" = "$installerVersion" ] || [[ ! -e "$OSInstaller/Contents/SharedSupport/InstallInfo.plist" ]]; 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" -eq 1 ]; then
            unsuccessfulDownload=0
            break
        fi
    else
        downloadInstaller
    fi
    unsuccessfulDownload=1
    ((loopCount++))
done

if [ "$unsuccessfulDownload" -eq 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 "$errorIcon" -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
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

## Because the parent bash script creates a new bash script using HEREDOC ( this <<EOF >that ),
## use a backslash before the dollar sign to avoid evaluating the variable (or command) as part of creating the script.

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

/bin/cat << EOF > "$finishOSInstallScriptFilePath"
#!/bin/bash
## First Run Script to remove the installer.


## Wait until /var/db/.AppleUpgrade disappears
while [ -e /var/db/.AppleUpgrade ];
do
    echo "$(date "+%a %h %d %H:%M:%S"): Waiting for /var/db/.AppleUpgrade to disappear." >> /usr/local/jamfps/firstbootupgrade.log
    sleep 60
done

## Wait until the upgrade process completes
INSTALLER_PROGRESS_PROCESS=$(pgrep -l "Installer Progress")
until [ "$INSTALLER_PROGRESS_PROCESS" = "" ];
do
    echo "$(date "+%a %h %d %H:%M:%S"): Waiting for Installer Progress to complete." >> /usr/local/jamfps/firstbootupgrade.log
    sleep 60
    INSTALLER_PROGRESS_PROCESS=$(pgrep -l "Installer Progress")
done
## Clean up files
/bin/rm -fr "$OSInstaller"
## Update Device Inventory
/usr/local/jamf/bin/jamf recon
## Remove LaunchAgent and LaunchDaemon
/bin/rm -f "$osinstallersetupdAgentSettingsFilePath"
/bin/rm -f "$osinstallersetupdDaemonSettingsFilePath"
## Remove Script
/bin/rm -fr /usr/local/jamfps
exit 0
EOF

/usr/sbin/chown root:admin "$finishOSInstallScriptFilePath"
/bin/chmod 755 "$finishOSInstallScriptFilePath"

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

/bin/cat << EOF > "$osinstallersetupdDaemonSettingsFilePath"
<?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>$finishOSInstallScriptFilePath</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
EOF

## Set the permission on the file just made.
/usr/sbin/chown root:wheel "$osinstallersetupdDaemonSettingsFilePath"
/bin/chmod 644 "$osinstallersetupdDaemonSettingsFilePath"

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# LAUNCH AGENT FOR FILEVAULT AUTHENTICATED REBOOTS
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if [ "$cancelFVAuthReboot" -eq 0 ]; then
    /bin/cat << EOP > "$osinstallersetupdAgentSettingsFilePath"
<?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/$binaryNameForOSInstallerSetup</string>
    </array>
</dict>
</plist>
EOP

    ## Set the permission on the file just made.
    /usr/sbin/chown root:wheel "$osinstallersetupdAgentSettingsFilePath"
    /bin/chmod 644 "$osinstallersetupdAgentSettingsFilePath"

fi

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

## Launch jamfHelper
jamfHelperPID=""
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" ] && 
   [ "$cancelFVAuthReboot" -eq 0 ] ; then
    userID=$( /usr/bin/id -u "${currentUser}" )
    /bin/launchctl bootstrap gui/"${userID}" /Library/LaunchAgents/com.apple.install.osinstallersetupd.plist
fi

## Set required startosinstall options
startosinstallOptions+=(
"--agreetolicense"
"--nointeraction"
"--pidtosignal $jamfHelperPID"
)

## Set version specific startosinstall options
if [ "$installerVersionMajor" -lt 14 ]; then
    # This variable may have space. Therefore, escape value with duble quotation
    startosinstallOptions+=("--applicationpath "$OSInstaller"")
fi

if [ "$installerVersionMajor" -gt 14 ]; then
    # The --forcequitapps option will force Self Service to quit, which prevents Self Service from cancelling a restart
    startosinstallOptions+=("--forcequitapps")
fi

## Check if eraseInstall is Enabled
if [ "$eraseInstall" -eq 1 ]; then
    startosinstallOptions+=("--eraseinstall")
    /bin/echo "Script is configured for Erase and Install of macOS."
fi

## Begin Upgrade
startosinstallCommand=""$OSInstaller/Contents/Resources/startosinstall" ${startosinstallOptions[*]} >> $osinstallLogfile 2>&1 &"
/bin/echo "Running a command as '$startosinstallCommand'..."
eval "$startosinstallCommand"

/bin/sleep 3

exit 0

950356e541bc4362bad9884c5d094ee4

3038ab6fe9884a10a407e01919515162

7598ca203799404195df71dbb93ec281

53a04372ce8f442d86a27afdea3edf06

mm2270
Legendary Contributor II

Ok, two other possible issues I can think of:

  1. It's possible the version of Install macOS Catalina.app on the machine is not actually 10.15.7. Since you are specifying 10.15.7 in $5, it's going to check to make sure there is a version match, and if not, will try to download the version from your custom trigger policy.
  2. I'm not sure if you need the backslashes in the installer path name in $4. I haven't tested this in a while now, but since this line: OSInstaller="$4" shows $4 is in double quotes, the backslashes escaping the spaces shouldn't be needed, I believe.

Can you check the installer version on the machine and also try without the backslashes and see if either of those help?