Files
Alte_Skripte/Update_macOS_with_deferral.sh
2026-02-16 15:05:15 +01:00

283 lines
12 KiB
Bash
Executable File

#!/bin/bash
##########################################################################
# Shellscript : macOS Update with deferral
# Autor : Andreas Vogel, NEXT Enterprise gmbh, 2021
##########################################################################
# set -x
setDeferral (){
BundleID="${1}"
DeferralType="${2}"
DeferralValue="${3}"
DeferralPlist="${4}"
if [[ "$DeferralType" == "date" ]]; then
DeferralDate="$(/usr/libexec/PlistBuddy -c "print :$BundleID:date" "$DeferralPlist" 2>/dev/null)"
# Set deferral date
if [[ -n "$DeferralDate" ]] && [[ ! "$DeferralDate" =~ "File Doesn't Exist" ]]; then
# /usr/libexec/PlistBuddy -c "set :$BundleID:date '07/04/2019 11:21:51 +0000'" "$DeferralPlist"
/usr/libexec/PlistBuddy -c "set :$BundleID:date $DeferralValue" "$DeferralPlist" 2>/dev/null
else
# /usr/libexec/PlistBuddy -c "add :$BundleID:date date '07/04/2019 11:21:51 +0000'" "$DeferralPlist"
/usr/libexec/PlistBuddy -c "add :$BundleID:date date $DeferralValue" "$DeferralPlist" 2>/dev/null
fi
elif [[ "$DeferralType" == "count" ]]; then
DeferralCount="$(/usr/libexec/PlistBuddy -c "print :$BundleID:count" "$DeferralPlist" 2>/dev/null)"
# Set deferral count
if [[ -n "$DeferralCount" ]] && [[ ! "$DeferralCount" =~ "File Doesn't Exist" ]]; then
/usr/libexec/PlistBuddy -c "set :$BundleID:count $DeferralValue" "$DeferralPlist" 2>/dev/null
else
/usr/libexec/PlistBuddy -c "add :$BundleID:count integer $DeferralValue" "$DeferralPlist" 2>/dev/null
fi
else
echo "Incorrect deferral type used."
exit 14
fi
}
OSMajorVersion="$(/usr/bin/sw_vers -productVersion | /usr/bin/cut -d '.' -f 1)"
DeferralPlist="/Library/Application Support/JAMF/com.custom.deferrals.plist"
BundleID="com.apple.SoftwareUpdate"
DeferralType="count"
DeferralValue="${4}"
if [[ -z "$DeferralValue" ]]; then
DeferralValue=3
fi
TimeOutinSec="${5}"
if [[ -z "$TimeOutinSec" ]]; then
TimeOutinSec="900"
fi
ITContact="${6}"
if [[ -z "$ITContact" ]]; then
ITContact="IT"
fi
CurrentDeferralValue="$(/usr/libexec/PlistBuddy -c "print :$BundleID:count" "$DeferralPlist" 2>/dev/null)"
# Set up the deferral value if it does not exist already
if [[ -z "$CurrentDeferralValue" ]] || [[ "$CurrentDeferralValue" =~ "File Doesn't Exist" ]]; then
setDeferral "$BundleID" "$DeferralType" "$DeferralValue" "$DeferralPlist"
CurrentDeferralValue="$(/usr/libexec/PlistBuddy -c "print :$BundleID:count" "$DeferralPlist" 2>/dev/null)"
fi
jamfHelper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"
jamf="/usr/local/bin/jamf"
AppleSUIcon="/System/Library/CoreServices/Install Command Line Developer Tools.app/Contents/Resources/SoftwareUpdate.icns"
CURRENT_USER=$(/usr/bin/python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "\n");')
realname=$(dscl . read /Users/$CURRENT_USER RealName | tail -n1)
ListOfSoftwareUpdates="/tmp/ListOfSoftwareUpdates"
######################### Messages #################################################
######################### find Language ############################################
Language=$(/usr/libexec/PlistBuddy -c 'print AppleLanguages:0' "/Users/${CURRENT_USER}/Library/Preferences/.GlobalPreferences.plist")
if [[ $Language = de* ]]; then
UserLanguage="de"
else
UserLanguage="en"
fi
######################### Message Box DE ###########################################
no_ac_power_de="Der Computer läuft derzeit im Akkubetrieb und ist nicht an eine Stromquelle angeschlossen. Schließen Sie den Computer an eine Stromquelle an und versuchen Sie es erneut."
StandardUpdatePrompt_de="Hallo, $realname für deinen Mac ist ein Betriebssystem-Update verfügbar. Klicken auf Fortfahren, um mit der Softwareaktualisierung fortzufahren und die Aktualisierung auszuführen. Wenn du den Vorgang zu diesem Zeitpunkt nicht starten kannst, kannst du den Vorgang um einen Tag verschieben. Wenn die Anzahl der Aufschübe aufgebraucht ist, wird die Aktualisierung erzwungen. Die Aktualisierung dauert etwa 30 Minuten.
Du kannst das macOS Software-Update jederzeit installieren
gehe hierzu  > System Preferences > Software Update
Verbleibende Anzahl der Verschiebungen: $CurrentDeferralValue"
ForcedUpdatePrompt_de="Hallo, $realname für deinen Mac sind Betriebssystem-Updates verfügbar, die einen Neustart erfordern. Du hast die Aktualisierungen bereits so oft wie möglich verschoben.
Bitte speichern deine Arbeit und klicken Sie auf Aktualisieren. Andernfalls wird diese Meldung ausgeblendet und der Computer wird automatisch neu gestartet."
PasswordInvalid_de="Passwort ungültig"
PasswordInvalidDescription_de="Du hast dreimal versucht, ein falsches Passwort einzugeben"
button1_de="Fortfahren"
button2_de="verschieben"
######################### Message Box EN ###########################################
no_ac_power_en="The computer is currently running on battery power and is not connected to a power source. Connect the computer to a power source and try again."
StandardUpdatePrompt_en="Hello, $realname for your Mac is an operating system update available. Click Continue to proceed with the software update and run the update. If you are unable to start the process at this time, you can postpone the process for one day. When the number of postponements is used up, the update will be forced. The update takes about 30 minutes to complete.
You can install the macOS software update at any time
by navigate  > System Preferences > Software Update
Remaining number of shifts: $CurrentDeferralValue"
ForcedUpdatePrompt_en="Hello, $realname for your Mac operating system updates are available that require a reboot. You have already moved the updates as many times as possible.
Please save your work and click Update. Otherwise, this message will disappear and the computer will restart automatically."
PasswordInvalid_en="Password Invalid"
PasswordInvalidDescription_en="You made three incorrect password attempts"
button1_en="Continue"
button2_en="delay"
no_ac_power=no_ac_power_${UserLanguage}
StandardUpdatePrompt=StandardUpdatePrompt_${UserLanguage}
ForcedUpdatePrompt=ForcedUpdatePrompt_${UserLanguage}
PasswordInvalid=PasswordInvalid_${UserLanguage}
PasswordInvalidDescription=PasswordInvalidDescription_${UserLanguage}
button1=button1_${UserLanguage}
button2=button2_${UserLanguage}
## Functions ##
powerCheck (){
# This is meant to be used when doing CLI update installs.
# Updates through the GUI can already determine its own requirements to proceed with
# the update process.
# Let's wait 5 minutes to see if computer gets plugged into power.
for (( i = 1; i <= 5; ++i )); do
if [[ "$(/usr/bin/pmset -g ps | /usr/bin/grep "Battery Power")" = "Now drawing from 'Battery Power'" ]]; then
echo "${!no_ac_power}"
/bin/sleep 60
else
return 0
fi
done
exit 11
}
runsoftwareupdate () {
expect <<EOF
spawn /usr/sbin/softwareupdate -iaR
expect "Password*"
send "$USER_PASS\r"
expect "Password:"
send "$USER_PASS\r"
expect EOF
EOF
}
updateCLI (){
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"
runAsUser() {
if [ "$LoggedInUser" != "loginwindow" ]; then
launchctl asuser "$uid" sudo -u "$LoggedInUser" "$@"
else
echo "no user logged in"
exit 1
fi
}
#Prompting logged in user for password
USER_PASS="$(launchctl asuser "$USER_ID" osascript -e 'display dialog "Please enter your Mac password to begin the Update:" default answer "" with title "macOS Update" giving up after 86400 with text buttons {"OK"} default button 1 with hidden answer' -e 'return text returned of result')"
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 Mac password to begin the Update:" default answer "" with title "macOS Update" 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."
HELPER=$("$jamfHelper" -windowType utility -title "${!PasswordInvalid}" -description "${!PasswordInvalidDescription}" -button1 "OK" -defaultButton 1 -timeout "300" -countdown -alignCountdown "right")
echo "Jamf Helper Exit Code: $HELPER"
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"
runsoftwareupdate
fi
}
fvStatusCheck (){
# Check to see if the encryption process is complete
FVStatus="$(/usr/bin/fdesetup status)"
if [[ $(/usr/bin/grep -q "Encryption in progress" <<< "$FVStatus") ]]; then
echo "The encryption process is not yet complete."
echo "$FVStatus"
exit 13
fi
}
# Store list of software updates in /tmp which gets cleared periodically by the OS and on restarts
/usr/sbin/softwareupdate -l 2>&1 > "$ListOfSoftwareUpdates"
UpdatesNoRestart=$(/bin/cat "$ListOfSoftwareUpdates" | /usr/bin/grep recommended | /usr/bin/grep -v restart | /usr/bin/cut -d , -f 1 | /usr/bin/sed -e 's/^[[:space:]]*//')
RestartRequired=$(/bin/cat "$ListOfSoftwareUpdates" | /usr/bin/grep restart | /usr/bin/grep -v '\*' | /usr/bin/cut -d , -f 1 | /usr/bin/sed -e 's/^[[:space:]]*//')
# Determine Secure Enclave version
SEPType="$(/usr/sbin/system_profiler SPiBridgeDataType | /usr/bin/awk -F: '/Model Name/ { gsub(/.*: /,""); print $0}')"
# Determine currently logged in user
LoggedInUser="$(/usr/sbin/scutil <<< "show State:/Users/ConsoleUser" | /usr/bin/awk '/Name :/ && ! /loginwindow/ { print $3 }')"
# Let's make sure FileVault isn't encrypting before proceeding any further
fvStatusCheck
# If there are no system updates, reset timer and exit script
if [[ "$UpdatesNoRestart" == "" ]] && [[ "$RestartRequired" == "" ]]; then
echo "No updates at this time."
setDeferral "$BundleID" "$DeferralType" "$DeferralValue" "$DeferralPlist"
exit 0
fi
##################################################################################################
############################ RUN Update ##########################################################
##################################################################################################
if [[ "$LoggedInUser" == "" ]]; then
echo "NO one is logged in"
exit 0
else
powerCheck
# Someone is logged in. Prompt if any updates require a restart ONLY IF the update timer has not reached zero
if [[ "$RestartRequired" != "" ]]; then
if [[ "$CurrentDeferralValue" -gt 0 ]]; then
# Reduce the timer by 1. The script will run again the next day
let CurrTimer=$CurrentDeferralValue-1
setDeferral "$BundleID" "$DeferralType" "$CurrTimer" "$DeferralPlist"
# If someone is logged in and they have not canceled $DeferralValue times already, prompt them to install updates that require a restart and state how many more times they can press 'cancel' before updates run automatically.
HELPER=$("$jamfHelper" -windowType utility -icon "$AppleSUIcon" -title "Apple Software Updates" -description "${!StandardUpdatePrompt}" -button1 "${!button1}" -button2 "${!button2}" -cancelButton "2" -defaultButton 2 -timeout "$TimeOutinSec" -countdown -alignCountdown "right")
echo "Jamf Helper Exit Code: $HELPER"
if [ "$HELPER" == "0" ]; then
updateCLI
fi
exit 0
else
HELPER=$("$jamfHelper" -windowType utility -icon "$AppleSUIcon" -title "Apple Software Update" -description "${!ForcedUpdatePrompt}" -button1 "Update" -defaultButton 1 -timeout "$TimeOutinSec" -countdown -alignCountdown "right")
echo "Jamf Helper Exit Code: $HELPER"
if [[ "$HELPER" == "0" ]] || [[ "$HELPER" == "239" ]]; then
updateCLI
fi
fi
fi
fi
exit 0