Maybe I spoke too soon.
With Monterey:
${jss}/JSSResource/computercommands/command/ScheduleOSUpdate/action/install/id/${jamfID}
Seemed to work pretty good on its own.
Adding
/bin/launchctl kickstart -k system/com.apple.softwareupdated
before the call seemed to make it work even better.
However it has done nothing for improving the situation on Big Sur endpoints.
/v1/macos-managed-software-updates/send-updates
In my limited testing this is working well for Monterey but it still very sporadic, leaning toward mostly not working for Big Sur endpoints.
I guess the solution is obvious, upgrade everything to Monterey.
Hi! With Monterrey pretty sure you want to POST to
https://instance.jamfcloud.com/api/v1/macos-managed-software-updates/send-updates
https://developer.jamf.com/jamf-pro/reference/post_v1-macos-managed-software-updates-send-updates
We have tested and it works. But the thing is it's kind of just a random wait until it starts.... Wish there was a way to intercept the process start (downloading update + starting preinstall before logout) from the syslog or such other and show a notification that it's starting. Could be anywhere from 30 seconds to 15 minutes before the machine randomly reboots on the user.
Hi! With Monterrey pretty sure you want to POST to
https://instance.jamfcloud.com/api/v1/macos-managed-software-updates/send-updates
https://developer.jamf.com/jamf-pro/reference/post_v1-macos-managed-software-updates-send-updates
We have tested and it works. But the thing is it's kind of just a random wait until it starts.... Wish there was a way to intercept the process start (downloading update + starting preinstall before logout) from the syslog or such other and show a notification that it's starting. Could be anywhere from 30 seconds to 15 minutes before the machine randomly reboots on the user.
@BlackGloveEng1 Funny you should mention, I've actually been working on an improved script that uses the new endpoint you mention (my version above was built prior to this) which also incorporates the use of an auth bearer token.
Here's what I'm testing now. It seems pretty solid, but I'm happy to receive any constructive criticism. The only issue I've noticed is the same as before, periodically a computer will go through the motions, but no update actually occurs. I can see in the logs the API call was successfully sent, so I think this is an Apple/MDM issue, not Jamf. Running a second time almost always fixes it up. Obviously use at your own risk, you can see I only schedule this to run off hours in our unique student lab environment, ymmv.
#!/bin/bash
### Execute macOS update via MDM API - LAB
### latest update 2022.06.30 -JonW
### Use auth bearer token and new /v1/macos-managed-software-updates/send-updates endpoint found in Jamf Pro API 10.38.0+
### This is primarily intended for off hours, scheduled macOS updates while at the login window.
### Script will warn any logged-in user with a 5 minute timer, but will NOT provide an option to defer.
### Updating in this fashion eliminates the requirement for a local admin password on Silicon and also works with Intel.
### Adapting a few ideas & tips from deflounder, @talkingmoose, & @bwoods - THANK YOU!
### https://derflounder.wordpress.com/2022/01/04/basic-authentication-deprecated-for-the-jamf-pro-classic-api/
### https://community.jamf.com/t5/jamf-pro/force-a-computer-restart-to-install-macos-updates/td-p/265982
### required API permissions
### Jamf Pro Server Objects: Computer (read only - to obtain device ID)
### Jamf Pro Server Actions: Send Computer Remote Command to Download and Install macOS Update
### Ensure policy uses MDM Restart with Kernel Cache Rebuild payload
### SECURITY NOTE!!!
### We're calling the API from the local computer, and passing the API username & password...
### which can potentially expose them to a savvy local user looking at system processes!
### In this case, risk is minimized by running only while at the login window and using a unique API user & pass with limited permissions.
#################################################################################
### Jamf policy script parameters
#################################################################################
jss="$4"
apiUser="$5"
apiPass="$6"
macOSversion="$7" ### OPTIONAL - specify a macOS version to install (if not specified, latest available will apply)
applyMajorUpdate="$8" ### OPTIONAL - allow major macOS version upgrade (specify true or false)
#################################################################################
### If a user is logged in, warn to save & logout within 5 minutes!
### As we only run late on weekends, chances are slim the user is actually active,
### more likely a stuck app has halted the automatic logout process, but just to be sure...
#################################################################################
loggedInUser=$( scutil <<< "show State:/Users/ConsoleUser" | awk '/Name
&& ! /loginwindow/ { print $3 }' )
if [[ -n "$loggedInUser" ]]; then
### Open JamfHelper dialog
buttonClicked=$(/Library/Application\\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper \\
-windowType utility \\
-title "Weekly MacOS Update Policy" \\
-heading "Attention! " \\
-description "Automatic logout to perform updates will occur in 5 minutes! To prevent data loss, save all files and logout immediately." \\
-defaultButton 1 \\
-button2 "OK" \\
-countdown \\
-timeout 300 \\
-alignCountdown center)
if [ $buttonClicked == 2 ]; then
### Button 2 clicked - user warning acknowledged
echo "User acknowledged, waiting 5 minutes for them to save & logout"
sleep 300
### Is user still logged in?
loggedInUser=$( scutil <<< "show State:/Users/ConsoleUser" | awk '/Name
&& ! /loginwindow/ { print $3 }' )
if [[ -n "$loggedInUser" ]]; then
echo "User acknowledged, but has yet to logout after 5 minutes, force logout now"
killall loginwindow ### No need to be delicate
sleep 30 ### wait for loginwindow to reload
else
echo "proceeding, user has logged out"
fi
else
### No click default = 1, the 5 minute countdown timed out
echo "proceeding, no user acknowledgement after 5 minutes, force logout now"
killall loginwindow ### No need to be delicate
sleep 30 ### wait for loginwindow to reload
fi
fi
#################################################################################
### kick softwareupdated, not required, but does 'seem' to help with success rate
#################################################################################
/bin/launchctl kickstart -k system/com.apple.softwareupdated
sleep 120 ### give it a few minutes to sort itself out
#################################################################################
### Generate Authorization Bearer Token
### (valid 30 minutes or until we invalidate)
#################################################################################
### (thanks again Der Flounder & @talkingmoose for the slick one-liner & parsing methods!)
if [[ $(/usr/bin/sw_vers -productVersion | awk -F . '{print $1}') -lt 12 ]]; then
### Pre Monterey, grab token & parse to remove quotes & expiration details
token=$(/usr/bin/curl -s "${jss}/api/v1/auth/token" -u "${apiUser}:${apiPass}" -X POST | python -c 'import sys, json; print json.load(sys.stdin)["token"]')
else
### As of Monterey, grab token and use updated plutil to pull raw token directly - no parsing necessary
token=$(/usr/bin/curl -s "${jss}/api/v1/auth/token" -s -u "${apiUser}:${apiPass}" -X POST | plutil -extract token raw -)
fi
echo "$token"
#################################################################################
### Determine Jamf Pro device id from the computer serial number (ID is required by /v1/macos-managed-software-updates endpoint)
### Note, I'm still unable to find a way to pull a device ID from the Pro API, continue using Classic for now.
#################################################################################
serialNumber=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')
deviceID=$(/usr/bin/curl -s "${jss}/JSSResource/computers/serialnumber/${serialNumber}" -H "Authorization: Bearer ${token}" -H "Accept: text/xml" | xmllint --xpath '/computer/general/id/text()' -)
echo "Device ID" ${deviceID}
#################################################################################
### Check current macOS, and attempt to apply updates
##################################################################################
### If optional specified macOS version is equal to the current macOS, we're already up to date, exit 0
current_macOS=$( sw_vers -productVersion )
if [[ "$7" == "$current_macOS" ]]; then
echo "Specified macOS is $7"
echo "current macOS is $current_macOS"
echo "No update necessary, macOS is already at our specified version"
exit 0
fi
### If optional script parameter $8 (allow major macOS upgrade) is not explicitely set to true, force default to be false
if [[ "$8" != "true" ]]; then
applyMajorUpdate="false"
echo "allow major macOS upgrade? $applyMajorUpdate"
else
echo "allow major macOS upgrade? $applyMajorUpdate"
fi
### If the optionally specified macOS version is NOT EQUAL to the current macOS, apply it, else apply the most recently available update.
### Note! We're not validating cases where the specified version may be lower than the currently installed version.
### The internal update process 'should' automatically ignore these attempts, but I've not yet tested the theory!
if [[ $7 != "" ]]; then
echo "attempting to apply specified macOS version $7"
/usr/bin/curl -s -X POST \\
--url "${jss}/api/v1/macos-managed-software-updates/send-updates" \\
--header "Authorization: Bearer ${token}" \\
--header "accept: application/json" \\
--header "Content-Type: application/json" \\
--data @<(cat <<EOF
{
"deviceIds": [
"$deviceID"
],
"maxDeferrals": 0,
"version": "$macOSversion",
"skipVersionVerification": true,
"applyMajorUpdate": $applyMajorUpdate,
"updateAction": "DOWNLOAD_AND_INSTALL",
"forceRestart": true
}
EOF
)
else
echo "attempting to apply the latest available macOS version"
/usr/bin/curl -s -X POST \\
--url "${jss}/api/v1/macos-managed-software-updates/send-updates" \\
--header "Authorization: Bearer ${token}" \\
--header "accept: application/json" \\
--header "Content-Type: application/json" \\
--data @<(cat <<EOF
{
"deviceIds": [
"$deviceID"
],
"maxDeferrals": 0,
"skipVersionVerification": true,
"applyMajorUpdate": $applyMajorUpdate,
"updateAction": "DOWNLOAD_AND_INSTALL",
"forceRestart": true
}
EOF
)
fi
#################################################################################
### Invalidate our token
#################################################################################
/usr/bin/curl -s "${jss}/api/v1/auth/invalidate-token" -H "Authorization: Bearer ${token}" -X POST
@BlackGloveEng1 Funny you should mention, I've actually been working on an improved script that uses the new endpoint you mention (my version above was built prior to this) which also incorporates the use of an auth bearer token.
Here's what I'm testing now. It seems pretty solid, but I'm happy to receive any constructive criticism. The only issue I've noticed is the same as before, periodically a computer will go through the motions, but no update actually occurs. I can see in the logs the API call was successfully sent, so I think this is an Apple/MDM issue, not Jamf. Running a second time almost always fixes it up. Obviously use at your own risk, you can see I only schedule this to run off hours in our unique student lab environment, ymmv.
#!/bin/bash
### Execute macOS update via MDM API - LAB
### latest update 2022.06.30 -JonW
### Use auth bearer token and new /v1/macos-managed-software-updates/send-updates endpoint found in Jamf Pro API 10.38.0+
### This is primarily intended for off hours, scheduled macOS updates while at the login window.
### Script will warn any logged-in user with a 5 minute timer, but will NOT provide an option to defer.
### Updating in this fashion eliminates the requirement for a local admin password on Silicon and also works with Intel.
### Adapting a few ideas & tips from deflounder, @talkingmoose, & @bwoods - THANK YOU!
### https://derflounder.wordpress.com/2022/01/04/basic-authentication-deprecated-for-the-jamf-pro-classic-api/
### https://community.jamf.com/t5/jamf-pro/force-a-computer-restart-to-install-macos-updates/td-p/265982
### required API permissions
### Jamf Pro Server Objects: Computer (read only - to obtain device ID)
### Jamf Pro Server Actions: Send Computer Remote Command to Download and Install macOS Update
### Ensure policy uses MDM Restart with Kernel Cache Rebuild payload
### SECURITY NOTE!!!
### We're calling the API from the local computer, and passing the API username & password...
### which can potentially expose them to a savvy local user looking at system processes!
### In this case, risk is minimized by running only while at the login window and using a unique API user & pass with limited permissions.
#################################################################################
### Jamf policy script parameters
#################################################################################
jss="$4"
apiUser="$5"
apiPass="$6"
macOSversion="$7" ### OPTIONAL - specify a macOS version to install (if not specified, latest available will apply)
applyMajorUpdate="$8" ### OPTIONAL - allow major macOS version upgrade (specify true or false)
#################################################################################
### If a user is logged in, warn to save & logout within 5 minutes!
### As we only run late on weekends, chances are slim the user is actually active,
### more likely a stuck app has halted the automatic logout process, but just to be sure...
#################################################################################
loggedInUser=$( scutil <<< "show State:/Users/ConsoleUser" | awk '/Name
&& ! /loginwindow/ { print $3 }' )
if [[ -n "$loggedInUser" ]]; then
### Open JamfHelper dialog
buttonClicked=$(/Library/Application\\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper \\
-windowType utility \\
-title "Weekly MacOS Update Policy" \\
-heading "Attention! " \\
-description "Automatic logout to perform updates will occur in 5 minutes! To prevent data loss, save all files and logout immediately." \\
-defaultButton 1 \\
-button2 "OK" \\
-countdown \\
-timeout 300 \\
-alignCountdown center)
if [ $buttonClicked == 2 ]; then
### Button 2 clicked - user warning acknowledged
echo "User acknowledged, waiting 5 minutes for them to save & logout"
sleep 300
### Is user still logged in?
loggedInUser=$( scutil <<< "show State:/Users/ConsoleUser" | awk '/Name
&& ! /loginwindow/ { print $3 }' )
if [[ -n "$loggedInUser" ]]; then
echo "User acknowledged, but has yet to logout after 5 minutes, force logout now"
killall loginwindow ### No need to be delicate
sleep 30 ### wait for loginwindow to reload
else
echo "proceeding, user has logged out"
fi
else
### No click default = 1, the 5 minute countdown timed out
echo "proceeding, no user acknowledgement after 5 minutes, force logout now"
killall loginwindow ### No need to be delicate
sleep 30 ### wait for loginwindow to reload
fi
fi
#################################################################################
### kick softwareupdated, not required, but does 'seem' to help with success rate
#################################################################################
/bin/launchctl kickstart -k system/com.apple.softwareupdated
sleep 120 ### give it a few minutes to sort itself out
#################################################################################
### Generate Authorization Bearer Token
### (valid 30 minutes or until we invalidate)
#################################################################################
### (thanks again Der Flounder & @talkingmoose for the slick one-liner & parsing methods!)
if [[ $(/usr/bin/sw_vers -productVersion | awk -F . '{print $1}') -lt 12 ]]; then
### Pre Monterey, grab token & parse to remove quotes & expiration details
token=$(/usr/bin/curl -s "${jss}/api/v1/auth/token" -u "${apiUser}:${apiPass}" -X POST | python -c 'import sys, json; print json.load(sys.stdin)["token"]')
else
### As of Monterey, grab token and use updated plutil to pull raw token directly - no parsing necessary
token=$(/usr/bin/curl -s "${jss}/api/v1/auth/token" -s -u "${apiUser}:${apiPass}" -X POST | plutil -extract token raw -)
fi
echo "$token"
#################################################################################
### Determine Jamf Pro device id from the computer serial number (ID is required by /v1/macos-managed-software-updates endpoint)
### Note, I'm still unable to find a way to pull a device ID from the Pro API, continue using Classic for now.
#################################################################################
serialNumber=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')
deviceID=$(/usr/bin/curl -s "${jss}/JSSResource/computers/serialnumber/${serialNumber}" -H "Authorization: Bearer ${token}" -H "Accept: text/xml" | xmllint --xpath '/computer/general/id/text()' -)
echo "Device ID" ${deviceID}
#################################################################################
### Check current macOS, and attempt to apply updates
##################################################################################
### If optional specified macOS version is equal to the current macOS, we're already up to date, exit 0
current_macOS=$( sw_vers -productVersion )
if [[ "$7" == "$current_macOS" ]]; then
echo "Specified macOS is $7"
echo "current macOS is $current_macOS"
echo "No update necessary, macOS is already at our specified version"
exit 0
fi
### If optional script parameter $8 (allow major macOS upgrade) is not explicitely set to true, force default to be false
if [[ "$8" != "true" ]]; then
applyMajorUpdate="false"
echo "allow major macOS upgrade? $applyMajorUpdate"
else
echo "allow major macOS upgrade? $applyMajorUpdate"
fi
### If the optionally specified macOS version is NOT EQUAL to the current macOS, apply it, else apply the most recently available update.
### Note! We're not validating cases where the specified version may be lower than the currently installed version.
### The internal update process 'should' automatically ignore these attempts, but I've not yet tested the theory!
if [[ $7 != "" ]]; then
echo "attempting to apply specified macOS version $7"
/usr/bin/curl -s -X POST \\
--url "${jss}/api/v1/macos-managed-software-updates/send-updates" \\
--header "Authorization: Bearer ${token}" \\
--header "accept: application/json" \\
--header "Content-Type: application/json" \\
--data @<(cat <<EOF
{
"deviceIds": [
"$deviceID"
],
"maxDeferrals": 0,
"version": "$macOSversion",
"skipVersionVerification": true,
"applyMajorUpdate": $applyMajorUpdate,
"updateAction": "DOWNLOAD_AND_INSTALL",
"forceRestart": true
}
EOF
)
else
echo "attempting to apply the latest available macOS version"
/usr/bin/curl -s -X POST \\
--url "${jss}/api/v1/macos-managed-software-updates/send-updates" \\
--header "Authorization: Bearer ${token}" \\
--header "accept: application/json" \\
--header "Content-Type: application/json" \\
--data @<(cat <<EOF
{
"deviceIds": [
"$deviceID"
],
"maxDeferrals": 0,
"skipVersionVerification": true,
"applyMajorUpdate": $applyMajorUpdate,
"updateAction": "DOWNLOAD_AND_INSTALL",
"forceRestart": true
}
EOF
)
fi
#################################################################################
### Invalidate our token
#################################################################################
/usr/bin/curl -s "${jss}/api/v1/auth/invalidate-token" -H "Authorization: Bearer ${token}" -X POST
Man, you are a rock star! This was next on my list to tackle. I have a great script to do erase and install, but getting user boxes updated when the user isn't an admin has been a giant pain in the butt. I am thinking I can scope this to an item in Self Service so the user can click on the item, have it display the dialog to save any work, then have it do the update...that would be awesome. For the labs, run it on a schedule.
Man, you are a rock star! This was next on my list to tackle. I have a great script to do erase and install, but getting user boxes updated when the user isn't an admin has been a giant pain in the butt. I am thinking I can scope this to an item in Self Service so the user can click on the item, have it display the dialog to save any work, then have it do the update...that would be awesome. For the labs, run it on a schedule.
@kwoodard Thanks! Sorry for the late response, it's been crazy busy around here. But yeah, my intention for this was unattended lab stations. It would need some tweaking for standard users due to the heavy-handed logout, and despite working well late at night in labs, there's no real indication that the MDM call is going to take effect. I still see about 10% of my computers randomly ignore the command and need a 2nd attempt. The command is successfully sent & logged, the update just doesn't kick off. I would probably suggest something else to notify/allow your standard users to kick off updates (upgrades are another issue).
I think this might be a good place to take this up.
I have been using the following API command with great success, to force OS updates in the middle of the night:
curl -X POST "https://ourJamfCloudAddress/api/v1/macos-managed-software-updates/send-updates" -H "accept: application/json" -H "Authorization: Bearer $api_token" -H "Content-Type: application/json" -d "{\\"deviceIds\\":[\\"${computerID}\\"],\\"maxDeferrals\\":0,\\"skipVersionVerification\\":true,\\"applyMajorUpdate\\":false,\\"updateAction\\":\\"DOWNLOAD_AND_INSTALL\\",\\"forceRestart\\":true}"
This has brought hundreds of computers up from 12.3 ish all the way up through 13.1 one point update at a time.
Personally I feel as if this command as written above should not have moved the machines from 12 to 13 given applyMajorUpdate is set to false. But it did. That's another story though.
Whats more upsetting is that now on 13.1 almost none of the intel machines will go to 13.2. Maybe 3 out of 300 made it. All of the Apple silicon macs did do the updates. I have way more intel classroom computers than Apple Silicon ones though.
Anyone else using a similar command and seeing similar results after 13.1 ?
Also of note, an MDM command with similarly optioned, pushed from the webui also does not work to move the intels past 13.1.
I think this might be a good place to take this up.
I have been using the following API command with great success, to force OS updates in the middle of the night:
curl -X POST "https://ourJamfCloudAddress/api/v1/macos-managed-software-updates/send-updates" -H "accept: application/json" -H "Authorization: Bearer $api_token" -H "Content-Type: application/json" -d "{\\"deviceIds\\":[\\"${computerID}\\"],\\"maxDeferrals\\":0,\\"skipVersionVerification\\":true,\\"applyMajorUpdate\\":false,\\"updateAction\\":\\"DOWNLOAD_AND_INSTALL\\",\\"forceRestart\\":true}"
This has brought hundreds of computers up from 12.3 ish all the way up through 13.1 one point update at a time.
Personally I feel as if this command as written above should not have moved the machines from 12 to 13 given applyMajorUpdate is set to false. But it did. That's another story though.
Whats more upsetting is that now on 13.1 almost none of the intel machines will go to 13.2. Maybe 3 out of 300 made it. All of the Apple silicon macs did do the updates. I have way more intel classroom computers than Apple Silicon ones though.
Anyone else using a similar command and seeing similar results after 13.1 ?
Also of note, an MDM command with similarly optioned, pushed from the webui also does not work to move the intels past 13.1.
Apple released macOS 13 as a minor update. So even if you didn't tick 'include Major updates', it would still upgrade the devices. 12.6.2 would upgrade whereas 12.6.3 would not, Apple realized what they had done and patched 12.6.3 to not auto upgrade, but for most people it was too late. There was an Apple Support article about this issue and how to block it but I can't find it right now.
I have the opposite problem, I have 25x arm64 iMacs stuck on 13.1
For Intel devices I try more draconian tactics using software update:
softwareupdate -i -a -R
If that doesn't work you can deploy the full 13.2 app installer out to the device and run the startosinstall command to auto upgrade the device.
/Applications/Install\\ macOS\\ Ventura.app/Contents/Resources/startosinstall --agreetolicense --nointeraction --forcequitapps
Add a restart command if its needed.
Use the 'Download Full Installer' app to download the 12.5Gb PKG installer from Apple.
https://github.com/scriptingosx/DownloadFullInstaller
You can also try:
softwareupdate --fetch-full-installer --full-installer-verson 13.2
and run the startosinstall command after that. Although this method isn't always successful at downloading the full installer app.
Also, make sure your Intel devices don't have pending MDM commands stuck in them (check the management tab is clear of pending & failed commands). If so, they will block the upgrade MDM commands as they will be added to the bottom of the list of pending commands. You may need to cancel all MDM commands on the Intel devices via a mass action before sending the upgrade OS MDM command.
Apple released macOS 13 as a minor update. So even if you didn't tick 'include Major updates', it would still upgrade the devices. 12.6.2 would upgrade whereas 12.6.3 would not, Apple realized what they had done and patched 12.6.3 to not auto upgrade, but for most people it was too late. There was an Apple Support article about this issue and how to block it but I can't find it right now.
I have the opposite problem, I have 25x arm64 iMacs stuck on 13.1
For Intel devices I try more draconian tactics using software update:
softwareupdate -i -a -R
If that doesn't work you can deploy the full 13.2 app installer out to the device and run the startosinstall command to auto upgrade the device.
/Applications/Install\\ macOS\\ Ventura.app/Contents/Resources/startosinstall --agreetolicense --nointeraction --forcequitapps
Add a restart command if its needed.
Use the 'Download Full Installer' app to download the 12.5Gb PKG installer from Apple.
https://github.com/scriptingosx/DownloadFullInstaller
You can also try:
softwareupdate --fetch-full-installer --full-installer-verson 13.2
and run the startosinstall command after that. Although this method isn't always successful at downloading the full installer app.
Also, make sure your Intel devices don't have pending MDM commands stuck in them (check the management tab is clear of pending & failed commands). If so, they will block the upgrade MDM commands as they will be added to the bottom of the list of pending commands. You may need to cancel all MDM commands on the Intel devices via a mass action before sending the upgrade OS MDM command.
"softwareupdate -i -a -R"
Hasn't worked for me since Big Sur. A couple machines will update, most all just reboot without applying the update.
"25x arm64 iMacs stuck on 13.1"
How are you trying to update them?
"full installer app"
Was trying to avoid that but it looks like that may be the only option right now.
"softwareupdate -i -a -R"
Hasn't worked for me since Big Sur. A couple machines will update, most all just reboot without applying the update.
"25x arm64 iMacs stuck on 13.1"
How are you trying to update them?
"full installer app"
Was trying to avoid that but it looks like that may be the only option right now.
yeah, that won't work for Apple silicon generally. use the API to push an MDM command is your best bet, or something like Nudge (https://github.com/macadmins/nudge) for user driven update, or Super (https://github.com/Macjutsu/super) for more IT driven side.
"softwareupdate -i -a -R"
Hasn't worked for me since Big Sur. A couple machines will update, most all just reboot without applying the update.
"25x arm64 iMacs stuck on 13.1"
How are you trying to update them?
"full installer app"
Was trying to avoid that but it looks like that may be the only option right now.
Big Sur has issues with software update.
In some cases it will say there are no updates available. In other cases it will say it cannot reach the Apple servers. Yet, if you manually upgrade the same machine to macOS 12 using the same wall port, it will suddenly reach the Apple servers and find updates. O_o? Big Sur has bugs I guess.
25x arm64 - Using a mass action update command via Jamf GUI.
They all went through ADE, are all supervised, all have a bootstrap token escrowed in Jamf, none have pending or failed MDM commands and are all checking in regularly with the Jamf server.
I think for me it may be a network related issue (SCEP) as arm64 devices upgrade fine at one campus (using a mass action) but not at the other campus for those specific rooms.
Full installer app
I have found this to be the most reliable option on older machines that wont play ball and that don't work properly or reliably with softwareupdate.
Hey all. Have you guys found that using a tool such as the "Download Full Installer" and then using script to run it as the most efficient way to get updates pushed? When going this route, would the user still be able to deny the update? As part of new security requirements at my company we have to be able to push the updates at "X" time and the user will be prompted, but can't defer past a certain time. We have a mixture of Apple and Intel silicon devices. I haven't specifically tested/tried any of the scripts posted here, but I am just trying to do more research before implementing any of them. Thanks.
@BlackGloveEng1 Funny you should mention, I've actually been working on an improved script that uses the new endpoint you mention (my version above was built prior to this) which also incorporates the use of an auth bearer token.
Here's what I'm testing now. It seems pretty solid, but I'm happy to receive any constructive criticism. The only issue I've noticed is the same as before, periodically a computer will go through the motions, but no update actually occurs. I can see in the logs the API call was successfully sent, so I think this is an Apple/MDM issue, not Jamf. Running a second time almost always fixes it up. Obviously use at your own risk, you can see I only schedule this to run off hours in our unique student lab environment, ymmv.
#!/bin/bash
### Execute macOS update via MDM API - LAB
### latest update 2022.06.30 -JonW
### Use auth bearer token and new /v1/macos-managed-software-updates/send-updates endpoint found in Jamf Pro API 10.38.0+
### This is primarily intended for off hours, scheduled macOS updates while at the login window.
### Script will warn any logged-in user with a 5 minute timer, but will NOT provide an option to defer.
### Updating in this fashion eliminates the requirement for a local admin password on Silicon and also works with Intel.
### Adapting a few ideas & tips from deflounder, @talkingmoose, & @bwoods - THANK YOU!
### https://derflounder.wordpress.com/2022/01/04/basic-authentication-deprecated-for-the-jamf-pro-classic-api/
### https://community.jamf.com/t5/jamf-pro/force-a-computer-restart-to-install-macos-updates/td-p/265982
### required API permissions
### Jamf Pro Server Objects: Computer (read only - to obtain device ID)
### Jamf Pro Server Actions: Send Computer Remote Command to Download and Install macOS Update
### Ensure policy uses MDM Restart with Kernel Cache Rebuild payload
### SECURITY NOTE!!!
### We're calling the API from the local computer, and passing the API username & password...
### which can potentially expose them to a savvy local user looking at system processes!
### In this case, risk is minimized by running only while at the login window and using a unique API user & pass with limited permissions.
#################################################################################
### Jamf policy script parameters
#################################################################################
jss="$4"
apiUser="$5"
apiPass="$6"
macOSversion="$7" ### OPTIONAL - specify a macOS version to install (if not specified, latest available will apply)
applyMajorUpdate="$8" ### OPTIONAL - allow major macOS version upgrade (specify true or false)
#################################################################################
### If a user is logged in, warn to save & logout within 5 minutes!
### As we only run late on weekends, chances are slim the user is actually active,
### more likely a stuck app has halted the automatic logout process, but just to be sure...
#################################################################################
loggedInUser=$( scutil <<< "show State:/Users/ConsoleUser" | awk '/Name
&& ! /loginwindow/ { print $3 }' )
if [[ -n "$loggedInUser" ]]; then
### Open JamfHelper dialog
buttonClicked=$(/Library/Application\\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper \\
-windowType utility \\
-title "Weekly MacOS Update Policy" \\
-heading "Attention! " \\
-description "Automatic logout to perform updates will occur in 5 minutes! To prevent data loss, save all files and logout immediately." \\
-defaultButton 1 \\
-button2 "OK" \\
-countdown \\
-timeout 300 \\
-alignCountdown center)
if [ $buttonClicked == 2 ]; then
### Button 2 clicked - user warning acknowledged
echo "User acknowledged, waiting 5 minutes for them to save & logout"
sleep 300
### Is user still logged in?
loggedInUser=$( scutil <<< "show State:/Users/ConsoleUser" | awk '/Name
&& ! /loginwindow/ { print $3 }' )
if [[ -n "$loggedInUser" ]]; then
echo "User acknowledged, but has yet to logout after 5 minutes, force logout now"
killall loginwindow ### No need to be delicate
sleep 30 ### wait for loginwindow to reload
else
echo "proceeding, user has logged out"
fi
else
### No click default = 1, the 5 minute countdown timed out
echo "proceeding, no user acknowledgement after 5 minutes, force logout now"
killall loginwindow ### No need to be delicate
sleep 30 ### wait for loginwindow to reload
fi
fi
#################################################################################
### kick softwareupdated, not required, but does 'seem' to help with success rate
#################################################################################
/bin/launchctl kickstart -k system/com.apple.softwareupdated
sleep 120 ### give it a few minutes to sort itself out
#################################################################################
### Generate Authorization Bearer Token
### (valid 30 minutes or until we invalidate)
#################################################################################
### (thanks again Der Flounder & @talkingmoose for the slick one-liner & parsing methods!)
if [[ $(/usr/bin/sw_vers -productVersion | awk -F . '{print $1}') -lt 12 ]]; then
### Pre Monterey, grab token & parse to remove quotes & expiration details
token=$(/usr/bin/curl -s "${jss}/api/v1/auth/token" -u "${apiUser}:${apiPass}" -X POST | python -c 'import sys, json; print json.load(sys.stdin)["token"]')
else
### As of Monterey, grab token and use updated plutil to pull raw token directly - no parsing necessary
token=$(/usr/bin/curl -s "${jss}/api/v1/auth/token" -s -u "${apiUser}:${apiPass}" -X POST | plutil -extract token raw -)
fi
echo "$token"
#################################################################################
### Determine Jamf Pro device id from the computer serial number (ID is required by /v1/macos-managed-software-updates endpoint)
### Note, I'm still unable to find a way to pull a device ID from the Pro API, continue using Classic for now.
#################################################################################
serialNumber=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')
deviceID=$(/usr/bin/curl -s "${jss}/JSSResource/computers/serialnumber/${serialNumber}" -H "Authorization: Bearer ${token}" -H "Accept: text/xml" | xmllint --xpath '/computer/general/id/text()' -)
echo "Device ID" ${deviceID}
#################################################################################
### Check current macOS, and attempt to apply updates
##################################################################################
### If optional specified macOS version is equal to the current macOS, we're already up to date, exit 0
current_macOS=$( sw_vers -productVersion )
if [[ "$7" == "$current_macOS" ]]; then
echo "Specified macOS is $7"
echo "current macOS is $current_macOS"
echo "No update necessary, macOS is already at our specified version"
exit 0
fi
### If optional script parameter $8 (allow major macOS upgrade) is not explicitely set to true, force default to be false
if [[ "$8" != "true" ]]; then
applyMajorUpdate="false"
echo "allow major macOS upgrade? $applyMajorUpdate"
else
echo "allow major macOS upgrade? $applyMajorUpdate"
fi
### If the optionally specified macOS version is NOT EQUAL to the current macOS, apply it, else apply the most recently available update.
### Note! We're not validating cases where the specified version may be lower than the currently installed version.
### The internal update process 'should' automatically ignore these attempts, but I've not yet tested the theory!
if [[ $7 != "" ]]; then
echo "attempting to apply specified macOS version $7"
/usr/bin/curl -s -X POST \\
--url "${jss}/api/v1/macos-managed-software-updates/send-updates" \\
--header "Authorization: Bearer ${token}" \\
--header "accept: application/json" \\
--header "Content-Type: application/json" \\
--data @<(cat <<EOF
{
"deviceIds": [
"$deviceID"
],
"maxDeferrals": 0,
"version": "$macOSversion",
"skipVersionVerification": true,
"applyMajorUpdate": $applyMajorUpdate,
"updateAction": "DOWNLOAD_AND_INSTALL",
"forceRestart": true
}
EOF
)
else
echo "attempting to apply the latest available macOS version"
/usr/bin/curl -s -X POST \\
--url "${jss}/api/v1/macos-managed-software-updates/send-updates" \\
--header "Authorization: Bearer ${token}" \\
--header "accept: application/json" \\
--header "Content-Type: application/json" \\
--data @<(cat <<EOF
{
"deviceIds": [
"$deviceID"
],
"maxDeferrals": 0,
"skipVersionVerification": true,
"applyMajorUpdate": $applyMajorUpdate,
"updateAction": "DOWNLOAD_AND_INSTALL",
"forceRestart": true
}
EOF
)
fi
#################################################################################
### Invalidate our token
#################################################################################
/usr/bin/curl -s "${jss}/api/v1/auth/invalidate-token" -H "Authorization: Bearer ${token}" -X POST
Hey Jon. I am attempting to implement your script for our MacOS updates. I am new to JAMF and Mac administration so bear with me. First, I can get the logout prompt to work and it will logout the user, but I think I might have the parameters for $4 $5 and $6 incorrect. For $4 I have our jss url https://mycompany.jamfcloud.com/ ; for $5 and $6 I am using our admin account that we have on all managed devices. So the current flow of everything is that it will log the user out automatically after the timer expires, but the updates never download and install automatically. Any potential help would be greatly appreciated. Thanks.
"softwareupdate -i -a -R"
Hasn't worked for me since Big Sur. A couple machines will update, most all just reboot without applying the update.
"25x arm64 iMacs stuck on 13.1"
How are you trying to update them?
"full installer app"
Was trying to avoid that but it looks like that may be the only option right now.
-ir --verbose
has been working for me on intel machines. Still working on Silicon.
Morning All
Just testing this scripit out on some of our M1 devices can anyone help with what this means,
Script result: eyJhbGciOiJIUzI1NiJ9.eyJhdXRoZW50aWNhdGVkLWFwcCI6IkdFTkVSSUMiLCJhdXRoZW50aWNhdGlvbi10eXBlIjoiSlNTIiwiZ3JvdXBzIjpbXSwic3ViamVjdC10eXBlIjoiSlNTX1VTRVJfSUQiLCJ0b2tlbi11dWlkIjoiMTZhZGQ3MmMtNjc3Ny00OTE2LTk5OWYtNGI5MzdhZTY3ZTEzIiwibGRhcC1zZXJ2ZXItaWQiOi0xLCJzdWIiOiI2IiwiZXhwIjoxNjkxMzk5MzMwfQ.poPO9MR8WkBRU4Eusfp0TDraRPl9eUNDBk5qcpNEq0E
Device ID 2824 allow major macOS upgrade? false attempting to apply the latest available macOS version { "processManagerUuids" : [ "d4bb3d33-8747-4912-9282-7c106bc7be29" ], "errors" : [ ]
Thanks
Morning All
Just testing this scripit out on some of our M1 devices can anyone help with what this means,
Script result: eyJhbGciOiJIUzI1NiJ9.eyJhdXRoZW50aWNhdGVkLWFwcCI6IkdFTkVSSUMiLCJhdXRoZW50aWNhdGlvbi10eXBlIjoiSlNTIiwiZ3JvdXBzIjpbXSwic3ViamVjdC10eXBlIjoiSlNTX1VTRVJfSUQiLCJ0b2tlbi11dWlkIjoiMTZhZGQ3MmMtNjc3Ny00OTE2LTk5OWYtNGI5MzdhZTY3ZTEzIiwibGRhcC1zZXJ2ZXItaWQiOi0xLCJzdWIiOiI2IiwiZXhwIjoxNjkxMzk5MzMwfQ.poPO9MR8WkBRU4Eusfp0TDraRPl9eUNDBk5qcpNEq0E
Device ID 2824 allow major macOS upgrade? false attempting to apply the latest available macOS version { "processManagerUuids" : [ "d4bb3d33-8747-4912-9282-7c106bc7be29" ], "errors" : [ ]
Thanks
@tdenton: You may wish to check-out Nudge.
@tdenton: You may wish to check-out Nudge.
@dan-snelson Im looking for something that can be run independently as I was hoping to use this in lab based enviorments out of hours.
We currently use MDM software update workflows but its not very reliable.
It seems to be going through the motions but never seems to be update.
Thanks