Programmatic macOS updates for Apple Silicon

dan-snelson
Valued Contributor II

(Please pardon the piecemeal post; I'm presuming partial information is better than nothing.)


scheduleOSUpdate via the Jamf Pro API

Thanks to AppleCare pointing out that:

When running the softwareupdate command in a root shell on Apple Silicon users are being prompted for a password. This is expected behavior and the recommendation is to use the Schedule an OS Update command via MDM. This is the method to use if you want to update Apple Silicon Macs without requiring user credentials.

In other words:

if [[ "$arch" == "arm64" ]]; then
    scheduleOSUpdateViaAPI
else
    /usr/sbin/softwareupdate --install --all --include-config-data --restart --force
fi

In my limited testing, users are still prompted:
1dd859ae6a0d47459212605ed9035d25
0f66bc76c8164c1f8d4e61444960f217


Pending Feature Requests


Snippets

####################################################################################################
#
# Variables
#
####################################################################################################

jamfProURL="https://company.jamfcloud.com" # No trailing forward slash
apiUsername="${5}"
apiPasswordEncrypted="${6}"
computerSerialNumber=$( /usr/sbin/system_profiler SPHardwareDataType | /usr/bin/grep Serial | /usr/bin/awk '{print $NF}' )
arch=$( /usr/bin/arch )



####################################################################################################
#
# Functions
#
####################################################################################################

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# xpath tool changes in Big Sur
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function xpath() {

    # https://scriptingosx.com/2020/10/dealing-with-xpath-changes-in-big-sur/
    # Thanks, Armin!
    if [[ $(sw_vers -buildVersion) > "20A" ]]; then
        /usr/bin/xpath -e "$@"
    else
        /usr/bin/xpath "$@"
    fi

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Decrypt Password
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function decryptPassword() {
    /bin/echo "${1}" | /usr/bin/openssl enc -aes256 -d -a -A -S "${2}" -k "${3}"
}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Schedule OS Update via the API
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function scheduleOSUpdateViaAPI() {

    echo "Schedule OS Update via the API …"

    apiPassword=$( decryptPassword ${apiPasswordEncrypted} ${Salt} ${Passphrase} )
    jamfProCompID=$( /usr/bin/curl -s -u ${apiUsername}:${apiPassword} ${jamfProURL}/JSSResource/computers/serialnumber/${computerSerialNumber}/subset/general | xpath "/computer/general/id/text()" )

    # /usr/bin/curl -s -X POST -H "Content-Type: text/xml" -u ${apiUsername}:${apiPassword} ${jamfProURL}/JSSResource/computercommands/command/ScheduleOSUpdate/action/InstallForceRestart/id/${jamfProCompID}

    /usr/bin/curl -s -X POST -H "Content-Type: text/xml" -u ${apiUsername}:${apiPassword} ${jamfProURL}/JSSResource/computercommands/command/ScheduleOSUpdate/action/Default/id/${jamfProCompID}

}




####################################################################################################
#
# Program
#
####################################################################################################


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Force Software Update Snippet only
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

if [[ "$arch" == "arm64" ]]; then
    scheduleOSUpdateViaAPI
else
    /usr/sbin/softwareupdate --install --all --include-config-data --restart --force
fi

--
Dan
40 REPLIES 40

fredrik_virding
Contributor

Hi!

tested this, and ran into some issues!

Did you ever get an error like below:

line 57: ScriptLog: command not found
error reading input file

mismatched tag at line 10, column 2, byte 404:
<p>You can get technical details <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">here</a>.<br>
    Please continue your visit at our <a href="/">home page</a>.
</p>
=^
</body>
</html>
 at /System/Library/Perl/Extras/5.30/darwin-thread-multi-2level/XML/Parser.pm line 187.
<html>
<head>
    <title>Status page</title>
</head>
<body style="font-family: sans-serif;">
<p style="font-size: 1.2em;font-weight: bold;margin: 1em 0px;">Unauthorized</p>
<p>The request requires user authentication</p>
<p>You can get technical details <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">here</a>.<br>
    Please continue your visit at our <a href="/">home page</a>.
</p>
</body>
</html>

tkimpton
Valued Contributor II

@dan-snelson same error as well

tkimpton
Valued Contributor II

The issue is with the xpath -e. If you try this manually it still give the error hmmm....

dan-snelson
Valued Contributor II

Sorry for the delay, @fredrik.virding and @tkimpton; I replaced ScriptLog (an internal function) with echo.


--
Dan

fredrik_virding
Contributor

Hi @dan-snelson ill try the updated version and get back to you! Thanks for replying.

fredrik_virding
Contributor

Hi @dan-snelson

Still seeing similar issue. Perhaps after the Jamf 10.29 update, it might perform better?

fredrik_virding
Contributor

An update on this. Not too much difference. Anyone made any progress so far?

bradtchapman
Valued Contributor II

@dan-snelson , thank you for giving your time, talents, energy, etc... to solve this problem. Great script.

It will certainly be useful until Apple realizes what a pain this is and gives us something even more ... enterprise-y.

fredrik_virding
Contributor

Indeed, thanks @dan-snelson

Anyone still seeing this in 11.4 and Jamf 10.29?

#!/bin/sh
Script result: Schedule OS Update via the API …
error reading input file

mismatched tag at line 10, column 2, byte 404:
<p>You can get technical details <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">here</a>.<br>
    Please continue your visit at our <a href="/">home page</a>.
</p>
=^
</body>
</html>
 at /System/Library/Perl/Extras/5.30/darwin-thread-multi-2level/XML/Parser.pm line 187.
<html>
<head>
   <title>Status page</title>
</head>
<body style="font-family: sans-serif;">
<p style="font-size: 1.2em;font-weight: bold;margin: 1em 0px;">Not Found</p>
<p>The server has not found anything matching the request URI</p>
<p>You can get technical details <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5">here</a>.<br>
Please continue your visit at our <a href="/">home page</a>.
</p>
</body>
</html>

Lincolnep
New Contributor III

I am not getting that I get a http response 201 but the mac does not update 😞

I have rewritten that script into python3 as that is what i use to manage our mac fleet.

from the /var/log/install.log it looks like it is trying to install the update tho but ether not downloading it or not force restarting it to do the update.

Lincolnep
New Contributor III

2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: SUOSUShimController: Notification manager client, proceeding with countdown notification flow without confirmation
2021-06-03 09:54:20+08 Name softwareupdated[267]: No matching products found while calculating disk space required
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: SUAppStoreUpdateController: disk space required for updates is: 0 ()
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: <SUOSUProduct: MSU_UPDATE_20F71_patch_11.4> is already prepared, just require installationSize. Initial space req: 0, MSU space req: 4797581312
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: Disk already has enough free space for updates (required: 950009856, available: 449098330112)
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: Starting free space request (required: 950009856, available: 449098330112)
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: Done requesting free space from StorageManagement
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: SUOSUShimController: Start downloading updates: ( "MSU_UPDATE_20F71_patch_11.4" )
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: Sending authorization to notification service
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: SUAppStoreUpdateController: authorize
2021-06-03 09:54:20+08 Name system_installd[1137]: PackageKit: Adding client PKInstallDaemonClient pid=267, uid=200 (/System/Library/CoreServices/Software Update.app/Contents/Resources/softwareupdated)
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: SUOSUNotificationManagerController: Added progress & completion handlers to SUMN
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: SUOSUAuthenticationManager: Disabling local authentication requirement
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: Waiting for available updates to be initially populated
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: Done waiting for available updates to be initially populated
2021-06-03 09:54:20+08 Name softwareupdated[267]: SUOSUMobileSoftwareUpdateController: Download finished: (null)
2021-06-03 09:54:20+08 Name softwareupdated[267]: No matching products found while calculating disk space required
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: SUOSUShimController: SUCCESS starting download notification service
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: SUOSUNotificationManagerController: Restart countdown download complete; clearing progress and completion handlers
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: SUOSUNotificationManagerController: Invoke restart countdown download finished
2021-06-03 09:54:20+08 Name SoftwareUpdateNotificationManager[1126]: SUOSUNotificationManagerController: Restart countdown download complete; clearing progress and completion handlers
2021-06-03 09:54:54+08 Name softwareupdated[267]: SUOSUServiceDaemon: Connection invalidated!
2021-06-03 09:54:54+08 Name softwareupdated[267]: Removing client SUUpdateServiceClient pid=2975, uid=0, installAuth=NO rights=(), transactions=0 (/usr/libexec/mdmclient)

Lincolnep
New Contributor III

Might need some help from jamf to sort this one out...
ae137b18757643509d28f051104b01c6

Lincolnep
New Contributor III

Findings only the install command works and it will only work with a user is login.

It will take about 10 - 20min to get it to kick off/reboot.

Not going to work for patching labs 😞

nelsoni
Contributor II

In my own testing, the "Install" action results in the same error in Jamf that Lincolnep is experiencing, this is on both Apple Silicone and Intel Macs. I also get the error regardless if a user is logged in or not.

beeboo
Contributor

so this works, tested on Big Sur M1 machines

 

https://{{url}}/JSSResource/computercommands/command/ScheduleOSUpdate/action/install/id/:id

and while the command respects comma seperated values, anyone know how to get the information from an array to then do a one liner with commas using bash?

 

example: https://{{url}}/JSSResource/computercommands/command/ScheduleOSUpdate/action/install/id/9,100,92,1,500

jwaltonen
New Contributor

Doesn't work for me.

What I am seeing here from what you posted :

https://{{url}}/JSSResource/computercommands/command/ScheduleOSUpdate/action/install/id/:id

is a : before the id.  If I add that colon i get:

<p>Unable to match computer </p>

Issuing the command leaving the colon out yields, Unsupported InstallAction for this ProductKey, whether I use default, install, or InstallForceRestart.

@jwaltonen 

so the qualifiers include but not limited to:

1. big sur

2. managed

 

I have a smart group that i query and get their computer IDs for

then i run that command.

In my case, all those are true when I run the command

https://{{url}}/JSSResource/computercommands/command/ScheduleOSUpdate/action/install/id/136,332

 

Note: I am using classic API, run via Postman, and my instance is hosted, FWIW

jwaltonen
New Contributor

I didn't think bootstrap token escrow was a prerequisite for this to work but I got it to work on a machine that had bootstrap token escrowed.  My failures were on otherwise equal 11.4 machines that didn't have bootstrap escrowed.

interesting note, the API command and the OS update MDM remote command from the web interface both seem to take almost exactly 30 minutes to restart the computer and apply the update, even if the 11.6 update is already downloaded.  Not perfect, but i'll take over what I had yesterday.  Which was nothing. 

Lincolnep
New Contributor III

@jwaltonen Did you have to be login to the Mac for the update to work?

you dont, the api command runs and it kicks off regardless if they are logged in or not, at least from my testing.

they have to be online though, but otherwise it should be good.

jwaltonen
New Contributor

no.  after the 10.32 upgrade it works at the login window.  Just takes 30 minutes to occur after issuing the commands.

jonw
New Contributor III

@beeboo @jwaltonen Just curious as to why the api command is working for you and failing for us.  In our case (student 11.5.2/M1 lab stations) we suppress auto software updates via config profile, I wonder if this may be getting in the way of the mdm command?

do you have the config profile set to no auto update/check/download etc, and also with a X days deferral?

 

We have just recently set the deferral so indeed that might be the issue.

redacting specific info, what is the exact url you are using? is it the same as the one i posted with your instanced replaced?

you ensuring is https?

 

what, if any, is the error you get?

 

When i run it in postman, for example, i get an xml output of computer info as a form of confirmation.

If it fails, i get a failure message.

 

Any other info from url to output that you can share would help.

jonw
New Contributor III

@beeboo @jwaltonen Thanks for the ideas, I'm sure its some bugginess in our configuration, but it gives me hope that it's working for you.

I'm fairly confident the api call is getting through... I've tried a few iterations via command line, Postman and by script.  Jamf history indicates a 'ScheduleOSUpdate' command was received & it eventually clears itself from the pending list, the update itself just dies on the vine.  

Again, test stations (both Silicon & Intel @ 11.5.2) are at the login window when running the mdm command, bootstrap token verified escrowed on the server, Jamf 10.32.2.  Software update config profile is set to not autoupdate or download anything, and no deferrals are set in our Restrictions profile.

jwaltonen
New Contributor

I assume you JSS is at 10.32 or better.

This is the command I use, again only tried on intel.  But it works for sure.

/usr/bin/curl -s -X POST -H "Content-Type: text/xml" --header 'authorization: Basic '$creds'' ${jamfProURL}/JSSResource/computercommands/command/ScheduleOSUpdate/action/install/id/${jamfProCompID}

 

You probably need to have the bootstrap token escrowed on m1 to bypass the user prompt.

jonw
New Contributor III

@jwaltonen Yep, we're on 10.32.2 cloud, bootstrap token is escrowed, using the same api command as you.

I'm fairly certain our api user prefs are correct, and besides 'install' I've also tried actions: InstallASAP & InstallForceRestart.  It's really driving me crazy!

I should also mention it's failing for me on Intel as well.

jwaltonen
New Contributor

The only action i could get to work was just plain old "install".  The other resulted in the "Unsupported InstallAction for this ProductKey"

i wanna say thats what the verbiage says in postman, so i would go with that.

collection was from Jamf

jwaltonen
New Contributor

I feel like you are issuing the command correctly based on what you say you are observing in the JAMF console.

When I issue the command to an endpoint I see this in the console.

Screen Shot 2021-10-06 at 12.35.45 PM.png

Then after a minute it goes away

Screen Shot 2021-10-06 at 12.35.54 PM.png

 then i see this in management history

Screen Shot 2021-10-06 at 12.36.08 PM.png

then sometime over the course of the next hour, the update occurs.

On machines that dont have the bootstrap token escrowed, all of the above still occurs but the update never happens.

Otherwise all my machines that I have successfully tested on are, intel, supervised, bootstrap token escrowed.

I am unsure at this point if any of my successful tests have occurred on machines that did not come through DEP/Automated Device Enrollment/ASM whatever you call it, prestage.  I am thinking maybe all of my successes were enrolled through a prestage enrollment.  

 

jwaltonen
New Contributor

Strike that about the bootstrap token.  Just had success on a machine where it was NOT escrowed to the server.

jonw
New Contributor III

Yep!  That's exactly what I'm seeing in the Jamf console after issuing the mdm command and why I don't think the issue is with the api call.

However, I did finally get one to update- but in exactly the manner I DON'T want to happen.  I sent the command while at the login window.  Waited many hours... nothing... then logged in as a standard user.  After about 30 minutes the computer restarted without warning and performed the update to 11.6.  While it didn't need a local user to interact, this obviously won't fly in a lab/classroom setting.


These are brand new M1 iMacs all ADE (DEP) enrolled via Pre-Stage enrollment, and I can verify by Jamf console or command line that a bootstrap token is escrowed on the server.  

Interesting you got one to work without a token... maybe was an update that didn't require it?

jwaltonen
New Contributor

It was the 11.6 update.  The behavior you describe is what I was seeing pre 10.32 upgrade, with the user needing to be logged in.  

Ill try to test an M1 and report back.

jonw
New Contributor III

Thanks!  I appreciate your input!  Would you mind sharing your software update & deferment settings?  And, do you use NoMAD Login AD or Jamf Connect by any chance?  We use NoMAD Login and I'm starting to wonder if it might be getting in the way of updates at the login window?  

jwaltonen
New Contributor

We use plain nomad not the login variety.

Currently this is  how our classrooms are set.

Screen Shot 2021-10-06 at 2.30.48 PM.png

And I have another custom deferment profile deployed to try to stave off Monterey from being automatically delivered.

 <key>enforcedSoftwareUpdateMajorOSDeferredInstallDelay</key>
<integer>90</integer>
</dict> 

jonw
New Contributor III

Thanks, update settings on my current test stations are set the same, so that's probably a dead end.

jonw
New Contributor III

@jwaltonen @beeboo Back to testing and interestingly I've been able to get positive results by sending the mdm command via Postman whereas the same command via Jamf policy script goes nowhere (again, the console reports the command as pending & eventually clears itself, but the update never actually takes place at the login window).

I just wanted to say thanks again, at least now I know my command is functional and the problem is with macOS and/or Jamf.  If anyone following along experiences the same issues, I'd love to hear about it.

beeboo
Contributor

Yeah, just wanted to reiterate that doing it via the GUI is a lot more finicky and at least in the testing from my end so far, usually "goes through" but actually does nothing.

 

Ive relegated myself to the task of running a script to get all the JSS IDs of the machines in my smart group that determines out of data Big Sur machines, append a comma, then copy paste to postman.

 

I could just script the whole thing, but with with tech lockdown right now, ill just wait.

jonw
New Contributor III

Well, fwiw I did finally get a scripted version to work... the downside is the same thing failed on another identical test station.  So yay I guess?  At least now it's down to determining "why is this so unreliable?"

jwaltonen
New Contributor

Before I went on vacation last week, I felt like i was having very solid successes issuing the command.  Like I did 2 entire classrooms, and all the machines in each had updated to 11.6 in less than 2 hours.  I started working on this again yesterday and am unsure that I am having any success getting the updates to actually occur.  The OSupdate entries show up in the management history/logs but no updates.  Weird and sad.