Apple M1 issue with softwareupdate -aiR

gforsyth
New Contributor III

I currently leverage a smart group, softwareupdate -aiR, custom notifications and the deferral option for an automated OS patching workflow both myself and user base are really happy with.

In testing the m1 chipset I am finding softwareupdate -aiR isn't functional in the workflow. Looks like there is an additional prompt for a password prior to downloading??? Anyone seen this or have any ideas as to why?

263e24affc164d3eb6374f0c71b8557e

63 REPLIES 63

draeconis
New Contributor II

iOS and Apple Silicon both act the same with updates; they need to be approved by a user process, or via an APNS command.

You either have to pass credentials to this process using something like 'expect' (not a great idea), or rely on your MDM service to send download/download and install calls via an API call.

DBrowning
Valued Contributor II

Check this out.. Having the same issues. I'm able to use some trickery to get it working on Big Sur on Intel, but for M1, the updates are downloading but not installing.

gforsyth
New Contributor III

Ugh... The API call is something I was looking into but that actually throws the unit into a recovery mode and requires user credentials which is clunky and confusing from a UX perspective... I will keep digging and call Apple. Thanks to you both!

joseph_english
New Contributor II

Same issue with M1s. I've been using this setup for patching and it's super slick, but on the M1s, it stalls out because it's waiting for a password. :(

DBrowning
Valued Contributor II

I've got it working now with prompting the user for their password and then using an except script to run the softwareupdates -iaR command. Not the best thing in the world, but at least I can run the updates via command line. Only downside is if the user doesn't read the warning/prompt saying you'll be asked for your password and don't enter it. Then the command will not run.

kendalljjohnson
Contributor II

@DBrowning Would you mind sharing the logic you are using to utilize the user input? I have scripts that can prompt for user input, but don't know how to take that and pass it into the -iaR component.

DBrowning
Valued Contributor II

Here you go @kendalljjohnson

echo "Running updates for Apple Silicon Mac"
            expect -c "
                set timeout -1
                spawn login $LoggedInUser
                expect "Password:"
                send "{${USER_PASS}}"
                send 
                spawn sh -c {sudo /usr/sbin/softwareupdate -iaR}
                expect "Password:"
                send "{${USER_PASS}}"
                send 
                expect "Password:"
                send "{${USER_PASS}}"
                send 
                expect eof
                "

kendalljjohnson
Contributor II

Much appreciated, thanks!

user-yMHedFrxlU
New Contributor

The solution worked for me thanks to the community and the members for the solution.

EdLuo
Contributor II

@DBrowning I tried your script and I am getting this error as shown in the policy log. I'm trying to update my M1 MBA with 11.3.1 just released. What am I doing wrong? Is there a way to hide error output to prevent the password from being logged?

Script result: Password Check: PASSED
Running updates for Apple Silicon Mac
send: spawn id exp48 not open
    while executing
"send {MyPassword}”

EdLuo
Contributor II

Here is the full script that I am using. I made a few changes from script that I found on Jamf.
Credit goes to you and Mauricio
https://www.jamf.com/jamf-nation/discussions/35899/verify-password-is-correct

#!/bin/bash


#########################################################################################
#
# FUNCTIONS
#
#########################################################################################

wrongUserPassword() {
userResponce=$(sudo -u "$userName" osascript <<EOF
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
set theTextReturned to "nil"
set theIcon to POSIX file "/Users/Shared/logo.png" as alias
set appTitle to "macOS update"
set okTextButton to "OK"
set enterPassword to "Enter your password to start the update"
set passwordWrong to "Incorrect Password"
set errorPasswordText to passwordWrong & return & enterPassword
set theResponse to display dialog {errorPasswordText} default answer "" buttons {okTextButton} default button 1 with title {appTitle} with icon theIcon with hidden answer giving up after 600
set theTextReturned to the text returned of theResponse
if theResponse is gave up then
return "cancelled"
else if theTextReturned is "" then
return "nopassword"
else
return theTextReturned
end if
EOF
)
validatePassword "$userResponce"
}

noUserPassword() {
userResponce=$(sudo -u "$userName" osascript <<EOF
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
set theTextReturned to "nil"

set theIcon to POSIX file "/Users/Shared/logo.png" as alias
set appTitle to "macOS update"
set okTextButton to "OK"
set enterPassword to "Enter your password to start the update"
set passwordEmpty to "The password is empty."
set errorPasswordText to passwordEmpty & return & enterPassword
set theResponse to display dialog {errorPasswordText} default answer "" buttons {okTextButton} default button 1 with title {appTitle} with icon theIcon with hidden answer giving up after 600
set theTextReturned to the text returned of theResponse
if theResponse is gave up then
return "cancelled"
else if theTextReturned is "" then
return "nopassword"
else
return theTextReturned
end if

EOF
)
validatePassword "$userResponce"
}

promptUserPassword() {
userResponce=$(sudo -u "$userName" osascript <<EOF
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
set theTextReturned to "nil"
set theIcon to POSIX file "/Users/Shared/logo.png" as alias
set appTitle to "macOS update"
set okTextButton to "OK"
set changesText to "One or more Apple Updates are availalbe." & return & "It may take 30-60 minutes to complete." & return & "To continue with macOS update" & return & return & "Enter login password for $userName"
set theResponse to display dialog {changesText} default answer "" buttons {okTextButton} default button 1 with title {appTitle} with icon theIcon with hidden answer giving up after 600
set theTextReturned to the text returned of theResponse
if theResponse is gave up then
return "cancelled"
else if theTextReturned is "" then
return "nopassword"
else
return theTextReturned
end if

EOF
)
}

verifyPassword() {

    dscl . authonly "$userName" "$userResponce" &> /dev/null; resultCode=$?
    if [ "$resultCode" -eq 0 ];then
        echo "Password Check: PASSED"
    else
        # Prompt for User Password
        echo "Password Check: WRONG PASSWORD"
        wrongUserPassword
    fi

}

validatePassword() {

    case "$userResponce" in
        "nopassword" ) echo "Password Check: NO PASSWORD" & noUserPassword ;;
        "cancelled" ) echo "Password Check: Time Out" ;;
        * ) verifyPassword  ;;
    esac

}



##########################################################################################
#
# SCRIPT CONTENTS
#
##########################################################################################
# Get the Username of the currently logged user
userName=$(ls -la /dev/console | cut -d " " -f 4)

# Ask the logged user for the password
promptUserPassword "$userName"

# Check is password is correct
validatePassword "$userResponce"

if [ $userResponce = "cancelled" ]; then
    echo "Password entry was cancelled"
else
    echo "Running updates for Apple Silicon Mac"
    expect -c "
        set timeout -1
        log_user 0
        spawn login $userName
        expect "Password:"
        send "{${userResponce}}"
        send 
        spawn sh -c {sudo /usr/sbin/softwareupdate -iaR}
        expect "Password:"
        send "{${userResponce}}"
        send 
        expect "Password:"
        send "{${userResponce}}"
        send 
        expect eof
        "
fi

cucaracha
New Contributor III

Hi, I am currently getting this on a M1 MacBook Air using the above script. Can anyone help to execute the script fully?

Thx, Alex

Screen Shot 2022-01-22 at 12.54.50 PM.png

I had to edit out the blank send commands, like so:

AdminUser=$4
AdminPass=$5
#Hope this works for Intel & Apple Silicon
echo "Running updates"
expect -c "
    set timeout -1
    spawn login $AdminUser
    expect "Password:"
    send "{${AdminPass}}"
    spawn sh -c {sudo /usr/sbin/softwareupdate -iaR --verbose | tee -a /var/log/jamf.log}
    expect "Password:"
    send "{${AdminPass}}"
    expect "Password:"
    send "{${AdminPass}}"
    expect eof
    "

Credit to @DBrowning  

I figured the "send " parts of that little expect block weren't acting like newlines or returns or anything so I removed them.
Then I thought I'd just use a local admin:pass to run the update.  That way we get around the fact that our users don't have sudo rights.
It appears to be working on an intel I'm testing right now, and I'll test on an M1 as soon as I get a chance.
Note the parameter numbers so you don't have to have user names or passwords written into a script.
Hope that helps.

DBrowning
Valued Contributor II

@EdLuo Here is the code from my script that works. I'm not sure how not to show the password in the instance of a failure.

#!/bin/sh
LoggedInUser=`ls -l /dev/console | cut -d " " -f4`
archType=$(/usr/bin/arch)
CURRENT_USER="$(stat -f%Su /dev/console)"
USER_ID=$(id -u "$CURRENT_USER")
jamfHelper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"


#Prompting logged in user for password
        USER_PASS="$(launchctl asuser "$USER_ID" osascript -e 'display dialog "Please enter your computer password to begin the monthly patching process:" default answer "" with title "Monthly Patching Big Sur" giving up after 86400 with text buttons {"OK"} default button 1 with hidden answer' -e 'return text returned of result')"

        #Testing password.  Fails after 3 invalid attempts
        TRY=1
        until dscl /Search -authonly "$CURRENT_USER" "$USER_PASS" &>/dev/null; do
            (( TRY++ ))
            echo "Prompting $CURRENT_USER for their Mac password (attempt $TRY)..."
            USER_PASS="$(launchctl asuser "$USER_ID" osascript -e 'display dialog "Please enter your computer password to begin the monthly patching process:" default answer "" with title "Monthly Patching Big Sur" giving up after 86400 with text buttons {"OK"} default button 1 with hidden answer' -e 'return text returned of result')"
            if (( TRY >= 3 )); then
                echo "[ERROR] Password prompt unsuccessful after 3 attempts. Displaying "forgot password" message..."
                launchctl asuser "$USER_ID" "$jamfHelper" -windowType "utility" -title "Password Invalid" -description "You made three incorrect password attempts.  

                Please reach out to your local Desktop Support Group or Chat for assistance" -button1 'OK' -defaultButton 1 -timeout 300 -startlaunchd &>/dev/null &
                exit 1
            fi
        done

if [ $archType == "i386" ]; then
            echo "Running updates for Intel Mac"
            /usr/bin/su -l $LoggedInUser -c "echo $USER_PASS | sudo -S /usr/sbin/softwareupdate -iaR --verbose" | tee -a /var/log/jamf.log
        else
            echo "Running updates for Apple Silicon Mac"
            expect -c "
                set timeout -1
                spawn login $LoggedInUser
                expect "Password:"
                send "{${USER_PASS}}"
                send 
                spawn sh -c {sudo /usr/sbin/softwareupdate -iaR --verbose | tee -a /var/log/jamf.log}
                expect "Password:"
                send "{${USER_PASS}}"
                send 
                expect "Password:"
                send "{${USER_PASS}}"
                send 
                expect eof
                "
fi

fredrik_virding
Contributor

Hi,

Also trying this out.

Anyone else getting this on M1 Airs? (see image)

Also, possible to not post the password in the script result? Would love to not see the Users passwords.
8a7bbffa80c34ea082b6779de80edcc0

EdLuo
Contributor II

I got it working. Here is my update script minus some personalization.

#!/bin/bash


#########################################################################################
#
# FUNCTIONS
#
#########################################################################################

runAsUser() {  
    if [ "$currentUser" != "loginwindow" ]; then
        launchctl asuser "$uid" sudo -u "$currentUser" "$@"
    else
        echo "no user logged in"
        exit 1
    fi
}


wrongUserPassword() {
userResponce=$(runAsUser osascript <<EOF
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
set theIcon to POSIX file "/Users/Shared/PNG/Logo.png" as alias
set appTitle to "macOS update"
set okTextButton to "OK"
set enterPassword to "Enter your password to start the update"
set passwordWrong to "Incorrect Password"
set errorPasswordText to passwordWrong & return & enterPassword
set theResponse to display dialog {errorPasswordText} default answer "" buttons {okTextButton} default button 1 with title {appTitle} with icon theIcon with hidden answer giving up after 600
set theTextReturned to the text returned of theResponse
if theResponse is gave up then
return "cancelled"
else if theTextReturned is "" then
return "nopassword"
else
return theTextReturned
end if
EOF
)
validatePassword "$userResponce"
}


noUserPassword() {
userResponce=$(runAsUser osascript <<EOF
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
set theIcon to POSIX file "/Users/Shared/PNG/Logo.png" as alias
set appTitle to "macOS update"
set okTextButton to "OK"
set enterPassword to "Enter your password to start the update"
set passwordEmpty to "The password is empty."
set errorPasswordText to passwordEmpty & return & enterPassword
set theResponse to display dialog {errorPasswordText} default answer "" buttons {okTextButton} default button 1 with title {appTitle} with icon theIcon with hidden answer giving up after 600
set theTextReturned to the text returned of theResponse
if theResponse is gave up then
return "cancelled"
else if theTextReturned is "" then
return "nopassword"
else
return theTextReturned
end if
EOF
)
validatePassword "$userResponce"
}


promptUserPassword() {
userResponce=$(runAsUser osascript <<EOF
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
set theIcon to POSIX file "/Users/Shared/PNG/Logo.png" as alias
set appTitle to "macOS update"
set okTextButton to "OK"
set changesText to "One or more Apple Updates are available." & return & "Depending on the speed of the internet connection, it may take 30-90 minutes to complete." & return & return & "Warning! Update will take place in the background and a reboot will likely take place when done without warning."  & return & return &  "To continue with macOS update, enter login password for $currentUser"
set theResponse to display dialog {changesText} default answer "" buttons {okTextButton} default button 1 with title {appTitle} with icon theIcon with hidden answer giving up after 600
set theTextReturned to the text returned of theResponse
if theResponse is gave up then
return "cancelled"
else if theTextReturned is "" then
return "nopassword"
else
return theTextReturned
end if
EOF
)
}


verifyPassword() {
    dscl . authonly "$currentUser" "$userResponce" &> /dev/null; resultCode=$?
    if [ "$resultCode" -eq 0 ];then
        echo "Password Check: PASSED"
        # DO THE REST OF YOUR ACTIONS....
    else
        # Prompt for User Password
        echo "Password Check: WRONG PASSWORD"
        wrongUserPassword
    fi
}


validatePassword() {
    case "$userResponce" in
        "nopassword" ) echo "Password Check: NO PASSWORD" & noUserPassword ;;
        "cancelled" ) echo "Password Check: Time Out" ;;
        * ) verifyPassword  ;;
    esac
}


##########################################################################################
#
# SCRIPT CONTENTS
#
##########################################################################################

#Check for Company Logo
if [ -e  /Users/Shared/PNG/Logo.png ]; then
    echo "Logo exist"
else
    echo "Installing logo"
    # You will need to create a seperate policy that deploys your company logo with event trigger DeployLogo
    jamf policy -event DeployLogo
fi

# Get the Username of the currently logged user
currentUser=$( echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ { print $3 }' )
uid=$(id -u "$currentUser")
echo "Logged in user: $currentUser"

# Ask the logged user for the password
promptUserPassword "$currentUser"

# Check is password is correct
validatePassword "$userResponce"

# Automated Install of Update
if [ $userResponce = "cancelled" ]; then
    echo "Password entry was cancelled"
else
    echo "Running updates for Apple Silicon Mac"
    runAsUser expect -c "
        set timeout -1
        spawn sudo /usr/sbin/softwareupdate -iaR
        expect "Password:"
        send "$userResponce"
        expect "Password:"
        send "$userResponce"
        expect eof
        "
fi

cbruce
New Contributor III

@EdLuo Hello,  I'm not a scripter by far. I'm attempting to utilize your script.  I have created another package and added DeployLogo to Execute Command.  So this part works.  What else do I need to have occur to get patching underway for M1?  I'm not sure what 'expect script' does.  Can someone reach out to me to assist?  Thanks very much.

dlbrabb
New Contributor III

@EdLuo - Nice script! I did run this and it looks like Self Service needs to quit before it restarts.

EdLuo
Contributor II

I didn't use my script in Self Service. I just basically scoped it to Apple Silicon computer with one or more updates. I have also setup a deferral so our users can delay the installation.

sgrall
New Contributor III

Deleted

xan_ps
New Contributor

@EdLuousing the expect script, my M1 outputs that its "Restarting", but doesn't restart.
After reboot, I have to re-run it to download the update and install it which again might not re-start automatically. Did you face a similar issue?

EdLuo
Contributor II

I just try update my M1 from 11.5 to 11.5.1 and it kicked off the process without any issue.  It is still updating.  How are you running the script?  Policy Trigger, Self Service, or from Terminal?

xan_ps
New Contributor

It's an expect script and I trigger it via bash in background using: bash -c "script.exp"

 

#! /usr/bin/expect -f
set password "mypassword"
set timeout -1
exp_internal -f /tmp/expect.log 0
spawn sudo /usr/sbin/softwareupdate -iR "macOS Big Sur 11.5.1-20G80"
expect "Password*"
send "$password\r"
expect "Password*"
send "$password\r"
expect eof

 

Output:

Downloading: 98.56%
Downloading: 99.90%
Downloading: 100.00%
Downloaded: macOS Big Sur 11.5.1
Restarting...

 

Sometimes when it does restart, the OS isn't updated.

 

EdLuo
Contributor II

Not sure why it is not working for you.  I had trouble getting the expect command to work until I incorporated that runAsUser() function.  See if you can add that into your code.  I'm thinking that the softwareupdate -iR needs to be run with the logged in user's account.

cbruce
New Contributor III

 

 

xan_ps
New Contributor

.

rblaas
Contributor II

I maybe wrong or misreading the script.. 

But when you apple sudo the user must be on the Sudoers list (as in be an Admin on the machine) 

In our office users are NOT admins. we do have a local admin on every machine. 

That said , It is unclear to me why 'softwareupdate' should work like this. When I run the command manually it is just stuck with no output (other then downloading and installing updates)  

 

Guess apple does not like SysAdmins 🙂 

jlombardo
Contributor

When I added @EdLuo's script to my policy, I appear to be stuck in a loop.. Has anyone experienced this?

bwoods
Valued Contributor

If you don't want to prompt the user at all, you can make a bash or python script that runs the Download and Install Updates management command for you. Add the script to a user interaction policy  to give the user the option to defer the update. 

bwoods_0-1643053685442.png

 

 

apiUsername="apiaccount"
apiPassword="apipassword"
jamfProURL="https://yourorg.jamfcloud.com"
macSerial=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')
jamfProCompID=$(curl -s -u $apiUsername:$apiPassword -H "Accept: text/xml" "$jamfProURL"/JSSResource/computers/serialnumber/"$macSerial" | xmllint --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/install/id/${jamfProCompID}

 

 

cucaracha
New Contributor III

The script communicates but doesn't fully execute. The command completes but the computer doesn't update. I'm still on 11.6.2. I thought there was something wrong with:


action/Default/

 but I tried this one as well:

 /action/InstallForceRestart/

 

I'm a bit confused by the logs, it looks to me like it did try to install Big Sur 11.6.3 and succeeded:
default 2022-02-03 11:31:03.665716 -0800 SoftwareUpdateNotificationManager SUOSUNotificationUpdateService: Install did begin for updates: (
"<SUOSUProduct: MSU_UPDATE_20G415_patch_11.6.3>"
)
default 2022-02-03 11:31:03.665723 -0800 SoftwareUpdateNotificationManager SUOSUNotificationUpdateService: MDM install did begin
default 2022-02-03 11:31:03.665756 -0800 SoftwareUpdateNotificationManager MDM major status: {
"MSU_UPDATE_20G415_patch_11.6.3" = {
phase = downloading;
progress = 0;
};
phase = downloading;
productKeys = (
"MSU_UPDATE_20G415_patch_11.6.3"
);
progress = 0;
}
default 2022-02-03 11:31:03.774389 -0800 SoftwareUpdateNotificationManager SUOSUNotificationUpdateService: Install did finish successfully for updates (
"<SUOSUProduct: MSU_UPDATE_20G415_patch_11.6.3>"
)

bwoods
Valued Contributor

Use "install" instead of "Default". I need to fix my post.

EdLuo
Contributor II

I gave up on my script.  I'm using Nudge for macOS 11.x and 12.x.  It is fairly reliable.
https://marketplace.jamf.com/details/nudge/

 

nwagner
Contributor

I hate to revive an old thread, but I was curious to see if anyone settled on a way to install software updates, but still do it though self service?

We are working on the API call to initiate the MDM command that @bwoods posted, but we have some setup to do. We're a little (aka alot) behind on the OS and hardware front, we are running mostly Catalina and intel because the pandemic has had us working from home for two years and users, well you know users. But we are about to get a bunch of Apple Silicon machines.

Thanks!

cucaracha
New Contributor III

@bwoods is correct. I changed it to "install" after I spoke to JAMF support. I have had success everytime since then.

/action/install/

They told me this was their official recommendation for updating the OS. They shared this API doc. https://developer.jamf.com/jamf-pro/reference/createcomputercommandbycommandandaction

I was also told,

"The default actions for updates are "latest, non-major" version when done via the API.
The new feature in 10.36 will make major updates possible.

The reason 'InstallForceRestart' didn't work is because it isn't supported yet (it will be in 10.36), so it just generates a DownloadOnly action.

So instead we should use just 'Install" which generates an 'InstallASAP' action."

 

 

@bwoods @cucaracha When I run the command to actually install the update, I keep getting this response:

<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>

The api user I created works fine for getting the machine ID, so I dunno what I am doing wrong here.

Did I screwed something up with the settings in our JAMF Server for the account I put in here:

apiUsername="apiaccount"

 I don't want to open everything up, cause I won't know what worked and it's not very secure to have godmode enabled.

Any ideas? Thanks.

cucaracha
New Contributor III

I have everything turned on, but I would think "Send Computer Remote Command to Download and Install macOS Update" needs to be on. Under Privileges > Jamf Pro Server Actions. Also "View MDM command information in Jamf Pro API"

bwoods
Valued Contributor

It looks like your api account may not have the proper permissions. Give it a try with your admin creds for testing.

I tried it with a different user and I was able to run it as a local script and got to this output:

<?xml version="1.0" encoding="UTF-8"?><computer_command><command><name>ScheduleOSUpdateScan</name><command_uuid>5c3de1d2-ab73-40bf-8638-b58d67c154f4</command_uuid><computer_id>3695</computer_id></command></computer_command>

Then I got a pop-up that needed admin authentication for SoftwareUpdate to be allowed to make some change or other. I didn't get a screenshot, sorry. This is as far as I've gotten with trying to update an M1 with a script or policy.

Is the update just supposed to install right after I run this, or is there something else I need to do?
 Thanks!

bwoods
Valued Contributor

Are your bootstrap tokens escrowed and are your macs supervised? The update downloads and updates the computer automatically after about 20-40 minutes. (some have even reported longer)

bwoods_0-1644940140374.png