Skip to main content
Question

Force a Computer Restart to Install macOS Updates


Show first post

114 replies

Forum|alt.badge.img+7
  • Contributor
  • 19 replies
  • June 3, 2022

I was able to create the this policy work but it only works during the software Update have the option set to "Restart", how can you push it to make the initial call when the software Update is set to "Start". When I run this executiion it doesn't do anything at the time or start the download. Wondering in what I am missing here. 


bwoods
Forum|alt.badge.img+14
  • Author
  • Honored Contributor
  • 473 replies
  • June 6, 2022
eargueta wrote:

I was able to create the this policy work but it only works during the software Update have the option set to "Restart", how can you push it to make the initial call when the software Update is set to "Start". When I run this executiion it doesn't do anything at the time or start the download. Wondering in what I am missing here. 


@eargueta, please rephrase your question. I don't understand the issue you're having.


dvasquez
Forum|alt.badge.img+16
  • Valued Contributor
  • 318 replies
  • June 15, 2022

I am seeing a hiccup here when running the script:

launchctl /private/tmp/osUpdate.plist
		rm -rf /private/tmp/osUpdate.plist

I get the following output indicating this command "launchctl" is not being used correctly. Have you run into this?

I am trying to use the script to upgrade Big Sur to Monterey M1 type.

 echo 'User clicked Start Now'

User clicked Start Now

+ echo 'Initializing Software Update'

Initializing Software Update

+ rm -rf /Users/dvasqu29/logs/

+ launchctl /private/tmp/osUpdate.plist

Unrecognized subcommand: /private/tmp/osUpdate.plist

Usage: launchctl <subcommand> ... | help [subcommand]

Many subcommands take a target specifier that refers to a domain or service

within that domain. The available specifier forms are:

 

system/[service-name]

Targets the system-wide domain or service within. Root privileges are required

to make modifications.

 

user/<uid>/[service-name]

Targets the user domain or service within. A process running as the target user

may make modifications. Root may modify any user's domain. User domains do not

exist on iOS.

 

gui/<uid>/[service-name]

Targets the GUI domain or service within. Each GUI domain is associated with a

user domain, and a process running as the owner of that user domain may make

modifications. Root may modify any GUI domain. GUI domains do not exist on iOS.

 

session/<asid>/[service-name]

Targets a session domain or service within. A process running within the target

security audit session may make modifications. Root may modify any session

domain.

 

pid/<pid>/[service-name]

Targets a process domain or service within. Only the process which owns the

domain may modify it. Even root may not do so.

 

When using a legacy subcommand which manipulates a domain, the target domain is

inferred from the current execution context. When run as root (whether it is

via a root shell or sudo(1)), the target domain is assumed to be the

system-wide domain. When run from a normal user's shell, the target is assumed

to be the per-user domain for that current user.

 

 


bwoods
Forum|alt.badge.img+14
  • Author
  • Honored Contributor
  • 473 replies
  • June 17, 2022
dvasquez wrote:

I am seeing a hiccup here when running the script:

launchctl /private/tmp/osUpdate.plist
		rm -rf /private/tmp/osUpdate.plist

I get the following output indicating this command "launchctl" is not being used correctly. Have you run into this?

I am trying to use the script to upgrade Big Sur to Monterey M1 type.

 echo 'User clicked Start Now'

User clicked Start Now

+ echo 'Initializing Software Update'

Initializing Software Update

+ rm -rf /Users/dvasqu29/logs/

+ launchctl /private/tmp/osUpdate.plist

Unrecognized subcommand: /private/tmp/osUpdate.plist

Usage: launchctl <subcommand> ... | help [subcommand]

Many subcommands take a target specifier that refers to a domain or service

within that domain. The available specifier forms are:

 

system/[service-name]

Targets the system-wide domain or service within. Root privileges are required

to make modifications.

 

user/<uid>/[service-name]

Targets the user domain or service within. A process running as the target user

may make modifications. Root may modify any user's domain. User domains do not

exist on iOS.

 

gui/<uid>/[service-name]

Targets the GUI domain or service within. Each GUI domain is associated with a

user domain, and a process running as the owner of that user domain may make

modifications. Root may modify any GUI domain. GUI domains do not exist on iOS.

 

session/<asid>/[service-name]

Targets a session domain or service within. A process running within the target

security audit session may make modifications. Root may modify any session

domain.

 

pid/<pid>/[service-name]

Targets a process domain or service within. Only the process which owns the

domain may modify it. Even root may not do so.

 

When using a legacy subcommand which manipulates a domain, the target domain is

inferred from the current execution context. When run as root (whether it is

via a root shell or sudo(1)), the target domain is assumed to be the

system-wide domain. When run from a normal user's shell, the target is assumed

to be the per-user domain for that current user.

 

 


Looks like you need to choose to unload or unload your daemon and/or agent.


bwoods
Forum|alt.badge.img+14
  • Author
  • Honored Contributor
  • 473 replies
  • June 17, 2022
dvasquez wrote:

I am seeing a hiccup here when running the script:

launchctl /private/tmp/osUpdate.plist
		rm -rf /private/tmp/osUpdate.plist

I get the following output indicating this command "launchctl" is not being used correctly. Have you run into this?

I am trying to use the script to upgrade Big Sur to Monterey M1 type.

 echo 'User clicked Start Now'

User clicked Start Now

+ echo 'Initializing Software Update'

Initializing Software Update

+ rm -rf /Users/dvasqu29/logs/

+ launchctl /private/tmp/osUpdate.plist

Unrecognized subcommand: /private/tmp/osUpdate.plist

Usage: launchctl <subcommand> ... | help [subcommand]

Many subcommands take a target specifier that refers to a domain or service

within that domain. The available specifier forms are:

 

system/[service-name]

Targets the system-wide domain or service within. Root privileges are required

to make modifications.

 

user/<uid>/[service-name]

Targets the user domain or service within. A process running as the target user

may make modifications. Root may modify any user's domain. User domains do not

exist on iOS.

 

gui/<uid>/[service-name]

Targets the GUI domain or service within. Each GUI domain is associated with a

user domain, and a process running as the owner of that user domain may make

modifications. Root may modify any GUI domain. GUI domains do not exist on iOS.

 

session/<asid>/[service-name]

Targets a session domain or service within. A process running within the target

security audit session may make modifications. Root may modify any session

domain.

 

pid/<pid>/[service-name]

Targets a process domain or service within. Only the process which owns the

domain may modify it. Even root may not do so.

 

When using a legacy subcommand which manipulates a domain, the target domain is

inferred from the current execution context. When run as root (whether it is

via a root shell or sudo(1)), the target domain is assumed to be the

system-wide domain. When run from a normal user's shell, the target is assumed

to be the per-user domain for that current user.

 

 


Ah, I see that that's a mistake in the script. I'll add the unload above.


bwoods
Forum|alt.badge.img+14
  • Author
  • Honored Contributor
  • 473 replies
  • June 17, 2022
dvasquez wrote:

I am seeing a hiccup here when running the script:

launchctl /private/tmp/osUpdate.plist
		rm -rf /private/tmp/osUpdate.plist

I get the following output indicating this command "launchctl" is not being used correctly. Have you run into this?

I am trying to use the script to upgrade Big Sur to Monterey M1 type.

 echo 'User clicked Start Now'

User clicked Start Now

+ echo 'Initializing Software Update'

Initializing Software Update

+ rm -rf /Users/dvasqu29/logs/

+ launchctl /private/tmp/osUpdate.plist

Unrecognized subcommand: /private/tmp/osUpdate.plist

Usage: launchctl <subcommand> ... | help [subcommand]

Many subcommands take a target specifier that refers to a domain or service

within that domain. The available specifier forms are:

 

system/[service-name]

Targets the system-wide domain or service within. Root privileges are required

to make modifications.

 

user/<uid>/[service-name]

Targets the user domain or service within. A process running as the target user

may make modifications. Root may modify any user's domain. User domains do not

exist on iOS.

 

gui/<uid>/[service-name]

Targets the GUI domain or service within. Each GUI domain is associated with a

user domain, and a process running as the owner of that user domain may make

modifications. Root may modify any GUI domain. GUI domains do not exist on iOS.

 

session/<asid>/[service-name]

Targets a session domain or service within. A process running within the target

security audit session may make modifications. Root may modify any session

domain.

 

pid/<pid>/[service-name]

Targets a process domain or service within. Only the process which owns the

domain may modify it. Even root may not do so.

 

When using a legacy subcommand which manipulates a domain, the target domain is

inferred from the current execution context. When run as root (whether it is

via a root shell or sudo(1)), the target domain is assumed to be the

system-wide domain. When run from a normal user's shell, the target is assumed

to be the per-user domain for that current user.

 

 


@dvasquez I fixed it. Copy the script again in my previous post.


Forum|alt.badge.img+6
  • Contributor
  • 28 replies
  • June 17, 2022

@bwoods How do i go about using it for macOS11 to 12. I am getting the following error "ScheduleOSUpdate Unsupported InstallAction for this ProductKey"

 

This M1 2021. it was when i used it for inline updates


bwoods
Forum|alt.badge.img+14
  • Author
  • Honored Contributor
  • 473 replies
  • June 21, 2022
tegus232 wrote:

@bwoods How do i go about using it for macOS11 to 12. I am getting the following error "ScheduleOSUpdate Unsupported InstallAction for this ProductKey"

 

This M1 2021. it was when i used it for inline updates


It looks like the API doesn't support full OS Upgrades yet. I can't get that feature to work like it does in the GUI.


Forum|alt.badge.img+8
  • Contributor
  • 118 replies
  • June 22, 2022

So we are struggling also with the macOS updates 

This script looks somewhat helpful. 

But, Beside it is taking a long time.. The computer will still reboot suddenly without any warning.. 

I would like to send a download only command first and fire an install command when I know the download is finished. 

 

Is this possible?


bwoods
Forum|alt.badge.img+14
  • Author
  • Honored Contributor
  • 473 replies
  • June 23, 2022

@rblaas, you have to use my script to warn users beforehand. Otherwise the machine will just reboot without warning.

At this time, I don't recommend putting this into production. The reboot takes too long to happen. Best options at this point are to use Nudge or deploy and update with macOS Installers.


markopolo
Forum|alt.badge.img+8
  • Contributor
  • 57 replies
  • June 23, 2022
bwoods wrote:

@rblaas, you have to use my script to warn users beforehand. Otherwise the machine will just reboot without warning.

At this time, I don't recommend putting this into production. The reboot takes too long to happen. Best options at this point are to use Nudge or deploy and update with macOS Installers.


I find it works best with computers already on 12.3+ so it can take advantage of the built-in MaxUserDeferrals key and notifications to the user:

 


dvasquez
Forum|alt.badge.img+16
  • Valued Contributor
  • 318 replies
  • June 23, 2022
bwoods wrote:

@dvasquez I fixed it. Copy the script again in my previous post.


Ok, I will check it out. I get the keys and I see the connection to the API calls. But the Silicon laptops will just not update. So I'll try again. Thank you this was super helpful. For the record I did add the umload to mine but for some reason the laptops will nto upgrade. Anyway thanks!


bwoods
Forum|alt.badge.img+14
  • Author
  • Honored Contributor
  • 473 replies
  • June 23, 2022
markopolo wrote:

I find it works best with computers already on 12.3+ so it can take advantage of the built-in MaxUserDeferrals key and notifications to the user:

 


@markopolo , what is the behavior you're seeing once the max deferral limit is reached? Does the computer restart randomly or are you prompted to install during the evening hours?

Also, what is the average time for a machine to reboot on your end?


bwoods
Forum|alt.badge.img+14
  • Author
  • Honored Contributor
  • 473 replies
  • June 23, 2022
dvasquez wrote:

Ok, I will check it out. I get the keys and I see the connection to the API calls. But the Silicon laptops will just not update. So I'll try again. Thank you this was super helpful. For the record I did add the umload to mine but for some reason the laptops will nto upgrade. Anyway thanks!


@dvasquez when you run the command on a machine, are you seeing that the management command has run in Jamf Pro. Simply go to the management tab to check this.


bwoods
Forum|alt.badge.img+14
  • Author
  • Honored Contributor
  • 473 replies
  • June 23, 2022
rblaas wrote:

So we are struggling also with the macOS updates 

This script looks somewhat helpful. 

But, Beside it is taking a long time.. The computer will still reboot suddenly without any warning.. 

I would like to send a download only command first and fire an install command when I know the download is finished. 

 

Is this possible?


Also, there is no option to download beforehand and install later. It's always going to download and install the update in the same APNS command.


dvasquez
Forum|alt.badge.img+16
  • Valued Contributor
  • 318 replies
  • June 23, 2022
bwoods wrote:

@dvasquez when you run the command on a machine, are you seeing that the management command has run in Jamf Pro. Simply go to the management tab to check this.


I will look for that but in early testing, I did not see any progress there. 

 

I will test again. 


Forum|alt.badge.img+8
  • Contributor
  • 118 replies
  • June 24, 2022
bwoods wrote:

@rblaas, you have to use my script to warn users beforehand. Otherwise the machine will just reboot without warning.

At this time, I don't recommend putting this into production. The reboot takes too long to happen. Best options at this point are to use Nudge or deploy and update with macOS Installers.


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. 

 


bwoods
Forum|alt.badge.img+14
  • Author
  • Honored Contributor
  • 473 replies
  • June 24, 2022
rblaas wrote:

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. 

 


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.

 


markopolo
Forum|alt.badge.img+8
  • Contributor
  • 57 replies
  • June 24, 2022
bwoods wrote:

@markopolo , what is the behavior you're seeing once the max deferral limit is reached? Does the computer restart randomly or are you prompted to install during the evening hours?

Also, what is the average time for a machine to reboot on your end?


To be honest, it always ran the update at night in our testing so I wasn't able to observe it. It seems to pick a time when the computer is inactive to do the forced restart. I'll try to do some additional testing and let you know.


wakco11
Forum|alt.badge.img+9
  • Valued Contributor
  • 146 replies
  • June 27, 2022

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.


bwoods
Forum|alt.badge.img+14
  • Author
  • Honored Contributor
  • 473 replies
  • June 27, 2022

@wakco11 , when you have a moment, please post your process. Any help improving the script is much appreciated. Thanks!


Forum|alt.badge.img+1
  • New Contributor
  • 5 replies
  • July 11, 2022
bwoods wrote:

 

Thanks @nwagner! Let me know how your testing goes.


Hi @bwoods. Firstly, thank you for your work on this. I tested your script with a Jamf admin account in the Part B policy and seems to work really well! My question, do you know what privileges are needed for a non administrator Jamf account specifically to able to run this task?  

Cheers! 


stutz
Forum|alt.badge.img+5
  • Contributor
  • 78 replies
  • July 11, 2022
moussabl wrote:

Hi @bwoods. Firstly, thank you for your work on this. I tested your script with a Jamf admin account in the Part B policy and seems to work really well! My question, do you know what privileges are needed for a non administrator Jamf account specifically to able to run this task?  

Cheers! 


@moussabl Here are the JAMF account permissions I use for this script and it works for me.  

Account
Access Level - Full Access
Privilege Set - Custom


Privileges (everything is unchecked except for the following):
JAMF Pro Server Objects - Computers - Create+Read

JAMF Pro Server Actions - Send Computer Remote Command to Download and Install macOS Update - Checked


wakco11
Forum|alt.badge.img+9
  • Valued Contributor
  • 146 replies
  • July 12, 2022
bwoods wrote:

@wakco11 , when you have a moment, please post your process. Any help improving the script is much appreciated. Thanks!


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


bwoods
Forum|alt.badge.img+14
  • Author
  • Honored Contributor
  • 473 replies
  • July 12, 2022
wakco11 wrote:

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


Fancy stuff man. I like it.


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings