Mojave push through Policy

jhathcock
New Contributor III

So I'm trying to deploy Mojave through policy.

I got the installation file set up on my target workstations. However, I can't find the script talked about here:

http://kb.mit.edu/confluence/display/istcontrib/Jamf+Pro+-+Upgrading+Macs+to+latest+operating+system

does anyone know of a script for automating the installation of mojave so it can be run from a script policy?

Thanks!

18 REPLIES 18

calvins
New Contributor III

At it's simplest, it's just the installer with the --nointeraction switch.

#!/bin/sh
/Applications/Install macOS Mojave.app/Contents/Resources/startosinstall --nointeraction

mmyers
New Contributor

Maybe something along the lines of this:

#!/bin/sh

"/Applications/Install macOS Mojave.app/Contents/Resources/startosinstall" ‑‑agreetolicense &

I haven't tested this yet, but something like this should work.

bugsin
New Contributor II

instead of trying to push the update, would it be feasible to try nagging users who are not on the proper version to update via Jamf helper?

calvins
New Contributor III

That's kind of what we do. We roll with more a deferrals-based system but it'd be easy to remove that bit. Here's what I use to nag people (and eventually force them) to upgrade.

#!/bin/bash
#Parameters:
    #$4 is the number of deferrals to give the user.
    #$5 is the name of the app, shown in logs and used to uniquely name the deferral message.
    #$6 is the custom trigger of a policy that will cache the macOS Installer if it isn't found. Not strictly necessary, but the script will fail out if it can't find the installer.
    #$7 is the path to the macOS installer .app. ie. "/Applications/Install macOS High Sierra.app"
    #$8 is the major version the policy should be upgrading the machine to, used to bail on a machine that's already at or above this version. ie. "14" for Mojave, "13" for High Sierra, "12" for Sierra, etc.

#Configuration & Parameters
initialDeferralCount="${4}"                                                                                       #How many deferrals to give the user.
OS="${5}"                                                                                                     #For logging and naming the deferral counter file.
cachePolicy="${6}"                                                                                                #Jamf policy trigger for getting a macOS installer .app
installerPath="${7}"                                                                                          #Path to the macOS Installer .app file
targetVersion="${8}"                                                                                          #Major version to upgrade to. Just used to determine if the script should exit to prevent re-running an upgrade.
iconPath="/private/etc/Logo.icns"                                                                             #Path to the icon to use on the deferral prompt. If file is missing or not specified, an alternate non-icon'd window will be shown.
deferralTitle=""                                                                                              #Optional. Shown in the title bar of the deferral prompt.
deferralHeader="Upgrade to macOS $OS"
deferralMessage="An upgrade to macOS $OS is ready and available. 

Do you want to install this upgrade now or ask again later?

Note a restart is required immediately to finish the upgrade and typically takes under an hour."               #Dialog shown on the deferral prompt.
noDeferralMessage="An upgrade to macOS $OS is ready and required.

Note a restart is required immediately to finish the upgrade and typically takes under an hour.

Please save all work and then click Upgrade when ready."                                                       #Dialog shown on the no deferral prompt.
######################################################################################################################################################

check_version()
{
    majorVersion="$( sw_vers -productVersion | cut -d . -f 2 )"
    if [[ "$majorVersion" -ge "$targetVersion" ]];
        then
            echo "Already at or macOS major version $targetVersion"
            jamf recon
            exit 0
        else
            check_installer
    fi
}


check_installer()
{
    if [ -e "${installerPath}" ];
        then
            echo "$OS installer found."
            check_for_users
        else
            echo "$OS installer not found."
            jamf policy -event $cachePolicy
            if [ -e "${installerPath}" ];
                then
                    echo "$OS installer found after caching from Jamf."
                    check_for_users
                else
                    echo "$OS installer not found after attempting to cache from Jamf. Check policy and connectivity to DP."
                    exit 1
            fi
    fi
}


#Check if anyone is logged on
check_for_users()
{
    user="$( stat -f%Su /dev/console )"
    if [[ $( who | awk '{ print $2 }' | grep console ) ]]; 
        then
            dnd_Check
        else
            echo "Nobody is logged on, starting the macOS upgrade...."
            run_installer
    fi
}


#See if one-off DND is enabled for the logged in user.
dnd_Check()
{
    dndFile="$( ls /Users/$user/Library/Preferences/ByHost/com.apple.notificationcenterui.*.plist )"          #Plist to read for DND detection.

    #Some users don't have this plist file. It's generated the first time you do anything in notification center, so catch it here
    if [[ ! -f $dndFile ]];
        then
            echo "$user doesn't have a notification preference file. Usually that's because they've never used notification center."           #This also means they could not have set DND, so just run the check.
            check_deferrals
    fi

    #Check for one-off DND
    echo "Checking $user's DND status."
    dndOneOff="$( plutil -p $dndFile | grep -i -w "doNotDisturb" | awk '{print $3}' )"
        if [[ $dndOneOff == "1" ]];
            then
                echo "One-Off DND is enabled, stopping now."
                exit 0
            else
                echo "One-Off DND isn't enabled."
                check_deferrals
        fi
}


check_deferrals()
{
    deferralFolder="/Library/Application Support/JAMF/Deferrals"
    deferralFile="${deferralFolder}/${OS}_deferralCount"

    ## Create the deferral folder if missing.
    if [ ! -d "$deferralFolder" ]; then
        echo "Initial Deferral folder isn't present. Creating it..."
        mkdir "$deferralFolder"
    fi

    ## Create or read the deferral counter file.
    if [ -f "$deferralFile" ];
        then
            deferralsLeft=$(cat "${deferralFile}")
        else
            echo "No Deferral Counter file found. Creating it with initial value of ${initialDeferralCount}..."
            echo "$initialDeferralCount" > "$deferralFile"
            deferralsLeft="$initialDeferralCount"
    fi

    ## If the user has deferrals left, give them the prompt.
    if [[ "$deferralsLeft" -ge 1 ]]; 
        then
            display_deferral_prompt
    fi

    ## If no deferrals are left, just start the installer.
    if [[ "$deferralsLeft" -eq 0 ]]; 
        then
            echo "0 deferrals remaining."
            display_noDeferral_prompt
    fi
}


display_deferral_prompt()
{
    helper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"                                   #The jamfHelper binary
    helperDeferralsLeft=\n\n"You have $deferralsLeft deferral(s) remaining."
    helperDescription="$( echo -e "$deferralMessage$helperDeferralsLeft" )"                                                 #Echo the description to preserve formatting when we call it during the jamfHelper message.
    echo "Showing the deferral prompt."

    if [[ -f $iconPath ]];
        then
            helperReturn=$( "$helper" -windowType hud -icon "$iconPath" -lockHUD -heading "$deferralHeader" -alignHeading center -description "$helperDescription" -alignDescription center -button2 "Upgrade" -button1 "Defer")
        else
            #The specified logo file does NOT exist, run the exact same patch command without the icon switch.
            helperReturn=$( "$helper" -windowType hud -lockHUD -heading "$deferralHeader" -alignHeading center -description "$helperDescription" -alignDescription center -button2 "Upgrade" -button1 "Defer")
    fi

    if [[ $helperReturn == "239" ]];
        then
            echo "User force-closed the prompt. Relaunching."
            display_deferral_prompt
    fi

    if [[ $helperReturn == "2" ]];
        then
            echo "User chose to upgrade."
            run_installer
        else
            echo "User deferred. Next check will be at the execution frequency interval defined in this policy."
            newDeferralCount=$((deferralsLeft-1))
            echo "$newDeferralCount deferrals remaining."   
            echo "$newDeferralCount" > "$deferralFile"
            exit 0
    fi
}


display_noDeferral_prompt()
{
    helper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"                                   #The jamfHelper binary
    helperDeferralsLeft=\n\n"You have $deferralsLeft deferral(s) remaining."
    helperDescription="$( echo -e "$noDeferralMessage$helperDeferralsLeft" )"                                               #Echo the description to preserve formatting when we call it during the jamfHelper message.
    echo "Showing the deferral prompt."

    if [[ -f $iconPath ]];
        then
            helperReturn=$( "$helper" -windowType hud -icon "$iconPath" -lockHUD -title "$deferralTitle" -heading "$deferralHeader" -alignHeading center -description "$helperDescription" -alignDescription center -button2 "Upgrade" -button1 "Defer" -timeout 60)
        else
            #The specified logo file does NOT exist, run the exact same patch command without the icon switch.
            helperReturn=$( "$helper" -windowType hud -lockHUD -title "$deferralTitle" -heading "$deferralHeader" -alignHeading center -description "$helperDescription" -alignDescription center -button2 "Upgrade" -button1 "Upgrade" -timeout 60)
    fi

    if [[ $helperReturn == "239" ]];
        then
            echo "User force-closed the prompt. Resistance is futile."
            display_noDeferral_prompt
    fi

    if [[ $helperReturn == "0" ]];
        then
            echo "User hit defer with no deferrals remaining, or the window timed out and will be reset into the foreground and center."
            display_noDeferral_prompt
    fi

    if [[ $helperReturn == "2" ]];
        then
            echo "User chose to upgrade."
            run_installer
        else
            echo "Jamf Helper exit code: $helperReturn"
            exit 1
    fi
}


run_installer()
{
    #--nointeraction bypasses the license agreement and makes it run silently and auto apply to the boot drive.
    #--reboot delay isn't strictly necessary, but the client will frequently reboot before sending the log back to Jamf if it isn't delayed.
    #Specifying volume is not a requirement as of 10.12.0+
    echo "Starting macOS installer"
    "${installerPath}/Contents/Resources/startosinstall" --rebootdelay 5 --nointeraction &&
    exit $?
}


#Start by checking the current OS version isn't what we are trying to upgrade to.
check_version

MMartin1
New Contributor II

@calvins Can you share a screenshot of how your policy is setup?

calvins
New Contributor III

Just the script in this policy, no restart options or anything else: aed138bea511457ba3ce994e838a7220
And the parameter labels:
bca2276f0c73465aaca4d033d94fdb9c
And the "cache policy" mentioned is just a PKG installer for dropping the installer into the usual spot in /Applications, nothing special.

nunezjim
New Contributor II

Update:

This worked for me Thank You! My policy was configured incorrectly before.

Thanks

calvins
New Contributor III

Do you actually have the installer on the Mac in the path specified in parameter #7? If so, check you don't have any trailing spaces, typos, text case, etc in the parameter. Usually it's just "/Applications/Install macOS Mojave.app".

If you don't have the installer in that path, check the policy you referenced on parameter #6 to see if it actually ran and what the policy log says. Could be your policy didn't run, or the package/DMG in the policy didn't work.

JamfMyMac
Contributor

@calvins Can you share screenshot of the triggers? I am wondering how the machine will know when the OS is fully cashed and now proceed to install.

Thanks.

calvins
New Contributor III

@aaelic24 The installer script handles detecting the installer, I thought it was a bit easier instead of using smart groups and criteria based on the machine inventory, that's the "check_installer()" bit in the script above.

The installer itself is just a drag/drop of the installer. Just like this article except putting it into /Applications instead of /Users/Shared: https://www.jamf.com/blog/streamlining-your-macos-upgrade-process/

This is the cache policy that goes with it:
7e5aca4e941a4dcfaa76a739658f69ba
944dfa8ec9fe46c3a83f25cd2f334093
09d3fa67034d44248483ec4cf2154a68

Gabrielson
New Contributor II

This does not seem to work on a Yosemite machine I am testing. Parameter 8 is set to "14" but I get the error "Already at or macOS major version", then it exits.

calvins
New Contributor III

I've never tried it on something that old and don't have any handy. What does running sw_vers -productVersion give you?

Gabrielson
New Contributor II

It gives me the correct version: 10.10.5. I'll test it on Sierra.

Gabrielson
New Contributor II

I can't get my hands on Sierra right now so tested on El Cap 10.11.6. Same thing. Returned error "Already at or macOS major version", then it exits. (sw_vers -productVersion returns 10.11.6). I took on this project to get all Macs (about 200) upgraded to 10.14.4 because right now the place is a mess (Macs on 10.10 through 10.14). What macOS versions have you had success upgrading with this script?

Thanks!

calvins
New Contributor III

I just did one this afternoon going from 10.11 to 10.13, didn't run into that error. That part of the script is really simple, it just pulls the "11" out of 10.11.6 and compares it to 13 or 14 in your case. Maybe run it line by line and see where it gets hung up?

I've never tried it on 10.10, but 10.11/12/13 definitely worked for me and I did hundreds with it.

markymarknz
New Contributor

Hey Calvins,

Thanks for your work!

Just wondering what your Trigger settings and Execution settings are for the main policy and how you Scope the devices. Are you using a smart group?

Cheers,
Marcus

calvins
New Contributor III

@markymarknz, considering just Mojave, I have 2 policies:
1. Policy to cache the Mojave installer, which is just running a package to drop the Mojave.app into /Applications, custom trigger of "cache-mojave" only. Scoped to all machines, excluding machines that can't actually run it.
2. Policy to run the installation with deferral script, trigger of "upgrade-mojave" or Self Service, scoped to machines under 10.14, excluding machines that can't actually run it.

The smart groups involved:
1. OS under 10.14: That's just "Operating System Version" less than "10.14"
2. Mojave incompatible machines: This group kind of sucks at the moment. It's a list of the model identifiers that explicitly are NOT supported on Mojave, so there are 60 criteria like "Model is MacbookAir2,1" or "Model is Macmini2,1", etc. When I get around to it, I'm planning on replacing that smart group with a scripted extension attribute to check that list of models and spit out a boolean for Mojave Compatibility.

I've got another set of groups and policies just like these for High Sierra, with the addition of another policy to run the installation policy at check-in for those on 10.11 and under.

CorpIT_eB
Contributor II

How would this work with the "macOSUpd10.14.5.dmg" I am trying to push out the update without user interaction and in the back end and i have not been able to successfully accomplish this. Does anyone currently have a workflow or policy they can toss in that would get this going?

I tried using the smartgroup actions and it does not work
I tried pushing it out via policy and it executes even restarts the computer but does not intsall
Executing Policy macOS Patch Updates
Downloading https://use1-jcds.services.jamfcloud.com//download/19727f945eb74fb797d9d257fa52498e/macOSUpd10.14.5.dmg?token=689de70203904bb682ed91ae0e0e233b7tp5sgnys4g0rvbs9zg6eegbns35y4py...
Verifying DMG...
Verifying package integrity...
Installing macOSUpd10.14.5.dmg...
Closing package...
Blessing i386 macOS System on /...
Creating Reboot Script...

Anyone's assistance would be greatly appreciated.

Thanks in advance.