05-16-2022 12:34 PM - edited 06-23-2022 08:47 AM
In light of the new "Force a Computer Restart to Install macOS Updates" feature in Jamf Pro 10.38.0, I've decided to create a bash function that should make life easier for admins that want to force updates on M1 machines.
Please refer to the screenshot below for more information on this feature.
New to bearer tokens? Don't worry about it, I've already done the work for you. Simply fill in your api account data and let the function take care of the rest.
#!/bin/bash
# Server connection information
URL="https://url.jamfcloud.com"
username="apiusername"
password="apipassword"
# Determine Serial Number
serialNumber=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')
initializeSoftwareUpdate(){
# create base64-encoded credentials
encodedCredentials=$( printf "${username}:${password}" | /usr/bin/iconv -t ISO-8859-1 | /usr/bin/base64 -i - )
# Generate new auth token
authToken=$( curl -X POST "${URL}/api/v1/auth/token" -H "accept: application/json" -H "Authorization: Basic ${encodedCredentials}" )
# parse authToken for token, omit expiration
token=$(/usr/bin/awk -F \" 'NR==2{print $4}' <<< "$authToken" | /usr/bin/xargs)
echo ${token}
# Determine Jamf Pro device id
deviceID=$(curl -s -H "Accept: text/xml" -H "Authorization: Bearer ${token}" ${URL}/JSSResource/computers/serialnumber/"$serialNumber" | xmllint --xpath '/computer/general/id/text()' -)
echo ${deviceID}
# Execute software update
curl -X POST "${URL}/api/v1/macos-managed-software-updates/send-updates" -H "accept: application/json" -H "Authorization: Bearer ${token}" -H "Content-Type: application/json" -d "{\"deviceIds\":[\"${deviceID}\"],\"maxDeferrals\":0,\"version\":\"12.3.1\",\"skipVersionVerification\":true,\"applyMajorUpdate\":true,\"updateAction\":\"DOWNLOAD_AND_INSTALL\",\"forceRestart\":true}"
# Invalidate existing token and generate new token
curl -X POST "${URL}/api/v1/auth/keep-alive" -H "accept: application/json" -H "Authorization: Bearer ${token}"
}
initializeSoftwareUpdate
Upload this script in combination with a user interaction / jamfhelper dialog policy to start forcing updates again!!!
Lessons Learned 06/01/2022:
1. The update can take an extremely long time to kick off. I'm talking 1-2 hours +
2. While the Jamf Pro GUI can do full OS upgrades, it doesn't seem to be supported in the API.
Lessons Learned 06/23/2022:
1. I cannot recommend putting this into production. While my jamf helper script does guide the user through the update, The targeted device does not restart in a reasonable time.
2. At this time, the best options for Monterey updates and upgrades seems to be using Nudge or the startosinstall executable that comes packaged with macOS installers: Solved: Re: macOS installer script not working for Apple S... - Jamf Nation Community - 249859
Posted on 06-24-2022 05:43 AM
You misunderstood me :)
I am using your script but other then a warning (which will stay in view for 30-60 minutes) there is no warning when the restart actually takes place. So it is still a restart without a short notice warning.
Posted on 06-24-2022 07:26 AM
Yep, nothing you can do about that. That's the main downfall of MDM commands in my opinion. Word is, Apple is release more features to make the update process better though. So stay hopeful.
Posted on 06-26-2022 08:59 PM
I'm finding most of these scripts are performing a serial number search to find the computer id, which will be the bit that taxes the server, I haven't found where it is stored yet normally, but I have noticed that 'jamf recon' outputs the computer id, so I realised if I capture that and store it, we can skip the S/N search, grab the stored computer id, and get right on with sending the push command.
Posted on 06-27-2022 06:30 AM
@wakco , when you have a moment, please post your process. Any help improving the script is much appreciated. Thanks!
07-11-2022 05:22 PM - edited 07-11-2022 05:27 PM
Step 1: Grab the computer_id from a recon.
Like most of us we need to have Jamf getting inventory updates from computers. We have a large number of laptops, which causes a common issue of network errors being reported if we use the standard basic inventory update policy, as users on laptops often disconnect their laptop from the network in the middle of the inventory update. I resolved this by using the hidden command jamf scheduledTask to create a launchd plist in /Library/LaunchDaemons that would trigger the jamf recon similar to a check-in, so the logs of network errors end up in the computers system log instead of causing jamf to log failed inventory update attempts, when a laptop happens to be disconnected during an inventory update. I realised I could change this to a script that could capture the jamf recon output and store it somewhere i.e.
#!/bin/sh
# Create script
SCRIPTFILE="/Library/Scripts/InventoryScript"
MYSCRIPT="#!/bin/sh
# This is a simple script to perform an inventory update, and save the computer id
RECON=\"\$(/usr/local/bin/jamf recon -randomDelaySeconds 450)\"
if [[ \"\$RECON\" = *\"computer_id\"* ]]; then
echo \"\$RECON\" | grep computer_id | grep -o '[0-9]\\+' > '/Library/Application Support/JAMF/computer_id'
fi
"
echo "$MYSCRIPT" > "$SCRIPTFILE"
# Give it execute permissions
chmod ugo+x "$SCRIPTFILE"
# Make it a scheduled task, running once a day (1440 Minutes = 24 hours)
/usr/local/bin/jamf scheduledTask -command "$SCRIPTFILE" -name recon -runAtLoad -minute '*/1440/'
# Let jamf know it is all done
ps -axj | grep jamf
ls -l "$SCRIPTFILE"
ls -l /Library/LaunchDaemons/com.jamfsoftware.task.recon.plist
This would cause an inventory update once a day, and within 10 minutes of a computer starting up (450 seconds is about 7 minutes 30 seconds). and leaves the Jamf Computer ID stored in /Library/Application Support/JAMF/computer_id, as captured from the last line of jamf recon which tends to look like <computer_id>1234</computer_id> where 1234 is the Jamf Computer ID.
Step 2: Used the stored computer_id to send a push command.
Replacing:
deviceID=$(curl -s -H "Accept: text/xml" -H "Authorization: Bearer ${token}" ${URL}/JSSResource/computers/serialnumber/"$serialNumber" | xmllint --xpath '/computer/general/id/text()' -)
With:
deviceID=$(cat '/Library/Application Support/JAMF/computer_id')
And removing the Serial Number collection.
I am actually doing more than that, I'm checking the file exists, and forcing an inventory update to capture it again if it isn't there, but this provides the basic difference.
- Richard
Posted on 07-12-2022 06:36 AM
Fancy stuff man. I like it.
Posted on 07-29-2022 03:46 PM
Was playing around with this and granting the account read access to Computers, it outputs some information that's questionable. management_password, list of users, software detected, etc
Not the fastest to get ID. But it won't expose more information than what's needed.
Posted on 08-03-2022 09:30 AM
From going through this thread, are 3 policies needed to deploy the update? From what I'm reading it looks like one is needed for the update script, Part A and Part B?
Posted on 08-03-2022 06:17 PM
Only two policies are needed. One to load the launch daemon and the other to run the script.
Posted on 08-04-2022 07:38 AM
Sorry for the ignorance on this, very new to Jamf. I'm just creating part A(daemon) and then part B for the script?
Posted on 08-04-2022 07:40 AM
Correct, part A is creating and loading a launch daemon that then runs the script in part B.
Posted on 08-04-2022 08:07 AM
I must be doing something wrong, because Part A shows installed, but it's not kicking off B.
Posted on 08-04-2022 08:54 AM
Ensure that you've configured the parameter for part A and that the custom trigger in part B matches the trigger in part A. Are you familiar with positional parameters / custom triggers in Jamf?
Posted on 08-04-2022 09:29 AM
I'm familiar with custom triggers, but not so much regarding positional parameters. I have the trigger in part B set to updateOS.
Posted on 08-04-2022 09:42 AM
Also, if the user hit's start now and then locks there Mac, will the process finish or does it need to be logged on to?
Posted on 08-05-2022 07:54 AM
Sorry for all the questions. Is it possible to set part B to deploy without any user interaction? Trying to be more like our SCCM side of things. We typically send out communications informing users of updates that are coming at night. If possible, it would cool to set this to deploy at night without any user interaction.
08-05-2022 08:13 AM - edited 08-05-2022 08:41 AM
If you don't want to notify the user first, you can send a mass action command via Jamf. More info below:
Updating macOS Using a Mass Action - Managing macOS Updates | Jamf
Posted on 08-05-2022 11:14 AM
That was hit miss when we tested it. Your script worked, so I think we'll roll with that and just have to have some user interaction.
08-05-2022 11:36 AM - edited 08-05-2022 11:37 AM
That's very strange because my script is basically an MDM Command in API form. If you don't want any interaction you can copy my original function above and just trow it in a policy.
Posted on 08-09-2022 07:51 PM
When running either the Part B or your original function, does the user have to be logged on for the update complete?
Posted on 09-08-2022 12:58 PM
Yes sir.
Posted on 09-07-2022 07:08 PM
Hi @bwoods - I've noticed on my test Mac when rebooting the machine the osupdate.plist file disappears from tmp folder. The file is still in the tmp folder when testing with logging the user off which is great.
Would you know a solution on how we can make the file not disappear after a reboot? Thank you
Posted on 09-08-2022 01:00 PM
You need to change the path in the Launch Daemon to:
/Library/LaunchDaemons
Posted on 09-08-2022 01:01 PM
All of the highlighted paths below will need to be changed.
Posted on 09-07-2022 12:26 PM
just FYI you need to change ${osFullName} to $osFullName in the variables otherwise you will get 403 Access Denied when trying to edit the script
Posted on 09-08-2022 01:36 PM
I'm still having such a hard time for updates to deploy. We have a user that we deployed the script to a couple of weeks ago and under software updates, it's waiting to install, but it's prompting for a username and password and his logon info doesn't work. Is this something related to maybe the securetoken?
Posted on 12-08-2022 07:00 AM
I've got good results with this, better than Mass MDM Commands.
Posted on 12-14-2022 07:49 AM
@bwoods Really nice work, does this work for Ventura?
Is the syntax where you specify the version as below for 13.1 13.1.0 or 13.1
"version\":\"12.4\"
Posted on 12-20-2022 08:00 AM
@MatG I haven't tested this in quite a while. I switched to using Nudge. Some people are telling me that it's not working for Ventura.
Posted on 04-11-2023 07:29 AM
Hey
Did you have try with an Updates Script with the new Priorty MDM Key for forcing Updates?
Priority can only be configured on macOS 12.3 and above, for minor updates only. Any version below 12.3 is always Low and cannot be changed until prerequisites are met. When qualified, if not explicitly set, priority will default to High
Posted on 01-09-2024 07:24 AM
Well made. But unfortunately the function is no longer usable. :(
Posted on 01-09-2024 07:33 AM
Posted on 01-09-2024 07:41 AM
look to do Declarative Software updates via jamf
Posted on 01-09-2024 07:48 AM
We have that enabled in Sandbox and have seen issues since the Software Update is in Beta
Posted on 01-09-2024 07:58 AM
yeah there is an Apple bug. make sure devices are on 14.2 or later