diff --git a/.prettierrc.yaml b/.prettierrc.yaml
new file mode 100644
index 0000000..81559b9
--- /dev/null
+++ b/.prettierrc.yaml
@@ -0,0 +1,6 @@
+semi: false
+overrides:
+ - files:
+ - "*.md"
+ options:
+ tabWidth: 2
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ec0ede5..291ba89 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,26 +4,37 @@
No date
+## [2.1]
+
+21.04.2022
+
+- Remove `softwareupdate` downloading stage as can cause unexpected installation.
+- Bugfix for identifying updates that do not require a restart.
+- New `/Library/Scripts/nice_updater_status.txt` file that can be read by a Jamf Extension Attribute for easy checking of run status.
+- Changed default defer count to 8.
+- Changed default wait after previous update to 7 days.
+- Other minor bugfixes.
+
## [2.0.3]
21.05.2021
-- Bugfix for issue #1
+- Bugfix for issue #1
## [2.0.2]
12.05.2021
-- Runs `jamfHelper` as the current user (this may not be necessary - was introduced to try and fix a problem where the tool was not showing though was running).
-- Changed default defer count (back) to 10.
+- Runs `jamfHelper` as the current user (this may not be necessary - was introduced to try and fix a problem where the tool was not showing though was running).
+- Changed default defer count (back) to 10.
## [2.0.1]
30.04.2021
-- The uninstaller script now forgets the package.
-- A delay is introduced after a user closes the Software Update pane before bringing the dialog back. This is to primarily prevent the popup showing up while a restart is happening. (Ideally we would be able to check if the restart has been initiated, but that is not happening yet.)
-- Added the CHANGELOG.md file.
+- The uninstaller script now forgets the package.
+- A delay is introduced after a user closes the Software Update pane before bringing the dialog back. This is to primarily prevent the popup showing up while a restart is happening. (Ideally we would be able to check if the restart has been initiated, but that is not happening yet.)
+- Added the CHANGELOG.md file.
## [2.0]
@@ -44,9 +55,9 @@ Also, the last notification message no longer times out after 300s. It will stay
27.08.2019
-- Replaced StartInterval with StartCalendarInterval to ensure script starts regularly.
-- Created an uninstaller script
-- Created a post-install script for Jamf which will allow parameters to be overridden in a policy.
+- Replaced StartInterval with StartCalendarInterval to ensure script starts regularly.
+- Created an uninstaller script
+- Created a post-install script for Jamf which will allow parameters to be overridden in a policy.
## [1.6]
@@ -78,7 +89,8 @@ Changed the default button of the jamfHelper dialogs to Cancel, because after ti
Also shortened the timeout to 82800 from 99999 seconds to prevent overlap of two days' dialogs.
-[untagged]: https://github.com/grahampugh/nice-updater/compare/v2.0.3...HEAD
+[untagged]: https://github.com/grahampugh/nice-updater/compare/v2.1...HEAD
+[2.1]: https://github.com/grahampugh/nice-updater/compare/v2.0.3...v2.1
[2.0.3]: https://github.com/grahampugh/nice-updater/compare/v2.0.2...v2.0.3
[2.0.2]: https://github.com/grahampugh/nice-updater/compare/v2.0.1...v2.0.2
[2.0.1]: https://github.com/grahampugh/nice-updater/compare/v2.0...v2.0.1
diff --git a/build.sh b/build.sh
index 92e2ee2..83000f6 100755
--- a/build.sh
+++ b/build.sh
@@ -4,7 +4,7 @@
identifier="com.github.grahampugh.nice_updater"
# Default version of the build, you can leave this alone and specify as an argument like so: ./build.sh 1.7
-version="2.0.3"
+version="2.1"
# The title of the message that is displayed when software updates are in progress and a user is logged in
updateRequiredTitle="macOS Software Updates Required"
@@ -18,14 +18,17 @@ updateInProgressTitle="Software Update In Progress"
# The location of your log, keep in mind that if you nest the log into a folder that does not exist you'll need to mkdir -p the directory as well
log="/Library/Logs/Nice_Updater.log"
+# The location of the status file, keep in mind that if the folder does not exist you'll need to mkdir -p the directory as well
+EAFile="/Library/Scripts/nice_updater_status.txt"
+
# The number of days to check for updates after a full update has been performed
-afterFullUpdateDelayDayCount="14"
+afterFullUpdateDelayDayCount="7"
# The number of days to check for updates after a updates were checked, but no updates were available
afterEmptyUpdateDelayDayCount="3"
# The number of times to alert a single user prior to forcibly installing updates
-maxNotificationCount="10"
+maxNotificationCount="8"
# Calendar based start interval - hours and minutes.
startIntervalHour="13" # valid is 0-23. If left blank, daemon will launch every hour instead of once per day.
@@ -104,6 +107,7 @@ defaults write "$PWD/$preferenceFileName" UpdateRequiredTitle -string "$updateRe
defaults write "$PWD/$preferenceFileName" UpdateRequiredMessage -string "$updateRequiredMessage"
defaults write "$PWD/$preferenceFileName" UpdateInProgressTitle -string "$updateInProgressTitle"
defaults write "$PWD/$preferenceFileName" Log -string "$log"
+defaults write "$PWD/$preferenceFileName" EAFile -string "$EAFile"
defaults write "$PWD/$preferenceFileName" AfterFullUpdateDelayDayCount -int "$afterFullUpdateDelayDayCount"
defaults write "$PWD/$preferenceFileName" AfterEmptyUpdateDelayDayCount -int "$afterEmptyUpdateDelayDayCount"
defaults write "$PWD/$preferenceFileName" MaxNotificationCount -int "$maxNotificationCount"
@@ -127,6 +131,7 @@ if find "$PWD/custom_icon" -name "*.png" ; then
defaults write "$PWD/$preferenceFileName" IconCustomPath -string "$icon_path"
else
echo "Nothing found at $PWD/custom_icon/*.png"
+ defaults write "$PWD/$preferenceFileName" IconCustomPath -string ""
fi
# Copy the LaunchDaemon plists to the temp build directory
diff --git a/com.github.grahampugh.nice_updater.prefs.plist b/com.github.grahampugh.nice_updater.prefs.plist
index 3500c1c..0ce4845 100644
--- a/com.github.grahampugh.nice_updater.prefs.plist
+++ b/com.github.grahampugh.nice_updater.prefs.plist
@@ -5,15 +5,17 @@
AfterEmptyUpdateDelayDayCount
3
AfterFullUpdateDelayDayCount
- 14
+ 7
AlertTimeout
3540
+ EAFile
+ /Library/Scripts/nice_updater_status.txt
IconCustomPath
- /Library/Scripts/nice_updater_custom_icon.png
+
Log
/Library/Logs/Nice_Updater.log
MaxNotificationCount
- 10
+ 8
UpdateInProgressTitle
Software Update In Progress
UpdateRequiredMessage
diff --git a/nice_updater.sh b/nice_updater.sh
index 56a4f1b..6c66549 100755
--- a/nice_updater.sh
+++ b/nice_updater.sh
@@ -1,7 +1,7 @@
#!/bin/bash
# Nice Updater 2
-version="2.0.3"
+version="2.1.0"
# These variables will be automagically updated if you run build.sh, no need to modify them
preferenceFileFullPath="/Library/Preferences/com.github.grahampugh.nice_updater.prefs.plist"
@@ -11,6 +11,7 @@ helperTitle=$(defaults read "$preferenceFileFullPath" UpdateRequiredTitle)
helperDesc=$(defaults read "$preferenceFileFullPath" UpdateRequiredMessage)
alertTimeout=$(defaults read "$preferenceFileFullPath" AlertTimeout)
log=$(defaults read "$preferenceFileFullPath" Log)
+EAFile=$(defaults read "$preferenceFileFullPath" EAFile)
afterFullUpdateDelayDayCount=$(defaults read "$preferenceFileFullPath" AfterFullUpdateDelayDayCount)
afterEmptyUpdateDelayDayCount=$(defaults read "$preferenceFileFullPath" AfterEmptyUpdateDelayDayCount)
maxNotificationCount=$(defaults read "$preferenceFileFullPath" MaxNotificationCount)
@@ -37,34 +38,34 @@ writelog() {
/bin/echo "$DATE" " $1" >> "$log"
}
+write_status() {
+ /bin/echo "$1" > "$EAFile"
+}
+
finish() {
writelog "======== Finished $scriptName ========"
exit "$1"
}
random_delay() {
- delay_time=$(( (RANDOM % 60)+1 ))
- writelog "Delaying software update check by ${delay_time}s."
- sleep ${delay_time}s
+ delay_time=$(( (RANDOM % 10)+1 ))
+ writelog "Delaying software update check by ${delay_time}s"
+ # sleep ${delay_time}
}
record_last_full_update() {
- writelog "Done with update process; recording last full update time."
+ writelog "Done with update process; recording last full update time"
/usr/libexec/PlistBuddy -c "Delete :last_full_update_time" $preferenceFileFullPath 2> /dev/null
/usr/libexec/PlistBuddy -c "Add :last_full_update_time string $(date +%Y-%m-%d\ %H:%M:%S)" $preferenceFileFullPath
- writelog "Clearing user alert data."
+ writelog "Clearing user alert data"
/usr/libexec/PlistBuddy -c "Delete :users" $preferenceFileFullPath
- writelog "Clearing On-Demand Update Key."
+ writelog "Clearing On-Demand Update Key"
/usr/libexec/PlistBuddy -c "Delete :update_key" $preferenceFileFullPath 2> /dev/null
/usr/libexec/PlistBuddy -c "Add :update_key array" $preferenceFileFullPath 2> /dev/null
}
-trigger_nonrestart_updates() {
- /usr/sbin/softwareupdate --install "$1"
-}
-
open_software_update() {
/usr/bin/open -W /System/Library/PreferencePanes/SoftwareUpdate.prefPane &
suPID=$!
@@ -74,6 +75,7 @@ open_software_update() {
sleep 1
done
writelog "Software Update was closed"
+ write_status "Software Update was closed"
was_closed=1
}
@@ -88,7 +90,7 @@ compare_date() {
alert_user() {
local subtitle="$1"
- [[ "$notificationsLeft" == "1" ]] && local subtitle="1 remaining alert before auto-install."
+ [[ "$notificationsLeft" == "1" ]] && local subtitle="1 remaining deferral"
[[ "$notificationsLeft" == "0" ]] && local subtitle="No deferrals remaining! Click on \"Install Now\" to proceed"
if /usr/bin/pgrep jamfHelper ; then
@@ -126,18 +128,21 @@ alert_user() {
pkill jamfHelper
helperExitCode=1
else
- writelog "A button was pressed."
+ writelog "A button was pressed"
fi
fi
# writelog "Response: $helperExitCode"
if [[ $helperExitCode == 0 ]]; then
- writelog "User initiated installation."
+ writelog "User initiated installation"
+ write_status "User initiated installation"
open_software_update
elif [[ $helperExitCode == 2 ]]; then
- writelog "User cancelled installation."
+ writelog "User cancelled installation"
+ write_status "User cancelled installation"
else
- writelog "Alert timed out without response."
+ writelog "Alert timed out without response"
+ write_status "Alert timed out without response"
((notificationCount--))
fi
@@ -154,45 +159,59 @@ alert_logic() {
if [[ "$notificationCount" -ge "$maxNotificationCount" ]]; then
notificationsLeft="$((maxNotificationCount - notificationCount))"
writelog "$loggedInUser has been notified $notificationCount times; not waiting any longer."
- alert_user "$notificationsLeft remaining alerts before auto-install." "$notificationCount"
+ alert_user "$notificationsLeft remaining deferrals." "$notificationCount"
else
((notificationCount++))
notificationsLeft="$((maxNotificationCount - notificationCount))"
- writelog "$notificationsLeft remaining alerts before auto-install."
- alert_user "$notificationsLeft remaining alerts before auto-install." "$notificationCount"
+ writelog "$notificationsLeft remaining deferrals."
+ alert_user "$notificationsLeft remaining deferrals." "$notificationCount"
fi
}
update_check() {
osVersion=$( /usr/bin/sw_vers -productVersion )
writelog "Determining available Software Updates for macOS $osVersion..."
- updates=$(/usr/sbin/softwareupdate -l)
- updatesNoRestart=$(echo "$updates" | grep -v restart | grep -B1 recommended | grep -v recommended | grep -v "\-\-" | sed 's|.*\* ||g')
- updatesRestart=$(echo "$updates" | grep -i restart | grep -v '\*' | cut -d , -f 1)
- updateCount=$(echo "$updates" | grep -i -c recommended)
+ update_file="/tmp/nice_updater_updates.txt"
+ /usr/sbin/softwareupdate --list > "$update_file"
+
+ # create list of updates that do not require a restart
+ updatesNoRestart=()
+ while IFS= read -r line; do
+ if [[ -n "$line" ]]; then
+ updatesNoRestart+=("$line")
+ writelog "Added '$line' to list of updates that do not require a restart"
+ fi
+ done <<< "$(grep -v restart "$update_file" | grep -B1 'Recommended: YES' | grep -v -i Recommended | grep -v '\-\-' | sed 's|.*\* ||g' | sed 's|^Label: ||')"
+
+ # create list of updates that do require a restart
+ updatesRestart=()
+ while IFS= read -r line; do
+ if [[ -n "$line" ]]; then
+ updatesRestart+=("$line")
+ writelog "Added '$line' to list of updates that require a restart"
+ fi
+ done <<< "$(grep -B1 'Recommended: YES, Action: restart' "$update_file" | grep -v restart | grep -v '\-\-' | sed 's|.*\* ||g' | sed 's|^Label: ||')"
+
+ updateCount=$(grep -c "Recommended: YES" "$update_file")
if [[ "$updateCount" -gt "0" ]]; then
# Download the updates
- writelog "Downloading $updateCount update(s)..."
- /usr/sbin/softwareupdate --download --recommended | grep --line-buffered Downloaded | while read -r LINE; do writelog "$LINE"; done
+ # writelog "Downloading $updateCount update(s)..."
+ # /usr/sbin/softwareupdate --download "${updatesNoRestart[@]}" | grep --line-buffered Downloaded | while read -r LINE; do writelog "$LINE"; done
- # Don't waste the user's time - install any updates that do not require a restart first.
- if [[ -n "$updatesNoRestart" ]]; then
+ # install any updates that do not require a restart, as these do not require authentication.
+ if [[ "${#updatesNoRestart[@]}" -gt 0 ]]; then
writelog "Installing updates that DO NOT require a restart in the background..."
- while IFS='' read -r line; do
- writelog "Updating: $line"
- trigger_nonrestart_updates "$line"
- done <<< "$updatesNoRestart"
+ /usr/sbin/softwareupdate --install "${updatesNoRestart[@]}"
fi
# If the script moves past this point, a restart is required.
- if [[ -n "$updatesRestart" ]]; then
- writelog "A restart is required for remaining updates."
- # If no user is logged in, just update and restart. Check the user now as some time has past since the script began.
+ if [[ "${#updatesRestart[@]}" -gt 0 ]]; then
+ writelog "A restart is required for remaining updates"
+ # Abort if no user is logged in. Check the user now as some time has past since the script began.
loggedInUser=$(/usr/sbin/scutil <<< "show State:/Users/ConsoleUser" | /usr/bin/awk -F': ' '/[[:space:]]+Name[[:space:]]:/ { if ( $2 != "loginwindow" ) { print $2 }}')
- # loggedInUID=$(id -u "$loggedInUser")
if [[ "$loggedInUser" == "root" ]] || [[ -z "$loggedInUser" ]]; then
- writelog "No user logged in. Cannot proceed."
+ writelog "No user logged in. Cannot proceed"
else
# Getting here means a user is logged in, alert them that they will need to install and restart
alert_logic
@@ -204,11 +223,13 @@ update_check() {
fi
else
record_last_full_update
- writelog "No updates that require a restart available; exiting."
+ writelog "No updates that require a restart available; exiting"
+ write_status "No updates that require a restart available; exiting"
finish 0
fi
else
- writelog "No updates at this time; exiting."
+ writelog "No updates at this time; exiting"
+ write_status "No updates at this time; exiting"
/usr/libexec/PlistBuddy -c "Delete :last_empty_update_time" $preferenceFileFullPath 2> /dev/null
/usr/libexec/PlistBuddy -c "Add :last_empty_update_time string $(date +%Y-%m-%d\ %H:%M:%S)" $preferenceFileFullPath
/usr/libexec/PlistBuddy -c "Delete :users" $preferenceFileFullPath 2> /dev/null
@@ -225,7 +246,8 @@ main() {
# See if we are blocking updates, if so exit
updatesBlocked=$(/usr/libexec/PlistBuddy -c "Print :updates_blocked" $preferenceFileFullPath 2> /dev/null | xargs 2> /dev/null)
if [[ "$updatesBlocked" == "true" ]]; then
- writelog "Updates are blocked for this client at this time; exiting."
+ writelog "Updates are blocked for this client at this time; exiting"
+ write_status "Updates are blocked for this client at this time; exiting"
finish 0
fi
@@ -241,27 +263,29 @@ main() {
if [[ -n "$lastFullUpdateTime" ]]; then
daysSinceLastFullUpdate="$(compare_date "$lastFullUpdateTime")"
if [[ "$daysSinceLastFullUpdate" -ge "$afterFullUpdateDelayDayCount" ]]; then
- writelog "$afterFullUpdateDelayDayCount or more days have passed since last full update."
+ writelog "$afterFullUpdateDelayDayCount or more days have passed since last full update"
# delay script's actions by up to 1 min to prevent all computers running software update at the same time
random_delay
update_check
else
- writelog "Less than $afterFullUpdateDelayDayCount days since last full update; exiting."
+ writelog "Less than $afterFullUpdateDelayDayCount days since last full update; exiting"
+ write_status "Less than $afterFullUpdateDelayDayCount days since last full update; exiting"
finish 0
fi
elif [[ -n "$lastEmptyUpdateTime" ]]; then
daysSinceLastEmptyUpdate="$(compare_date "$lastEmptyUpdateTime")"
if [[ "$daysSinceLastEmptyUpdate" -ge "$afterEmptyUpdateDelayDayCount" ]]; then
- writelog "$afterEmptyUpdateDelayDayCount or more days have passed since last empty update check."
+ writelog "$afterEmptyUpdateDelayDayCount or more days have passed since last empty update check"
# delay script's actions by up to 1 min to prevent all computers running software update at the same time
random_delay
update_check
else
- writelog "Less than $afterEmptyUpdateDelayDayCount days since last empty update check; exiting."
+ writelog "Less than $afterEmptyUpdateDelayDayCount days since last empty update check; exiting"
+ write_status "Less than $afterEmptyUpdateDelayDayCount days since last empty update check; exiting"
finish 0
fi
else
- writelog "This device might not have performed a full update yet."
+ writelog "This device might not have performed a full update yet"
# delay script's actions by up to 1 min to prevent all computers running software update at the same time
random_delay
update_check
diff --git a/nice_updater_uninstall.sh b/nice_updater_uninstall.sh
index 0eb4e45..141cc2f 100755
--- a/nice_updater_uninstall.sh
+++ b/nice_updater_uninstall.sh
@@ -12,6 +12,7 @@ mainOnDemandDaemonPlist="/Library/LaunchDaemons/${identifier}_on_demand.plist"
watchPathsPlist="/Library/Preferences/${identifier}.trigger.plist"
preferenceFileFullPath="/Library/Preferences/${identifier}.prefs.plist"
iconPath="/Library/Scripts/nice_updater_custom_icon.png"
+EAFilePath="/Library/Scripts/nice_updater_status.txt"
scriptPath="/Library/Scripts/nice_updater.sh"
uninstallScriptPath="/Library/Scripts/nice_updater_uninstall.sh"
uninstallScriptName=$(basename "$uninstallScriptPath")
@@ -52,8 +53,10 @@ writelog "Deleting NiceUpdater Preferences..."
writelog "Deleting NiceUpdater files..."
-# Delete the main preferences file
+# Delete the icon file
[[ -e "$iconPath" ]] && rm -f "$iconPath"
+# Delete the status file
+[[ -e "$EAFilePath" ]] && rm -f "$iconPath"
# Delete the main preferences file
[[ -e "$scriptPath" ]] && rm -f "$scriptPath"
[[ -e "$uninstallScriptPath" ]] && rm -f "$uninstallScriptPath"
diff --git a/postinstall.sh b/postinstall.sh
index b09b96a..8534b1a 100644
--- a/postinstall.sh
+++ b/postinstall.sh
@@ -14,9 +14,9 @@ chown root:wheel /Library/Scripts/nice_updater.sh
chmod 755 /Library/Scripts/nice_updater.sh
chown root:wheel /Library/Scripts/nice_updater_uninstall.sh
chmod 755 /Library/Scripts/nice_updater_uninstall.sh
-if [[ -f /Library/Scripts/custom_icon.png ]]; then
- chown root:wheel /Library/Scripts/custom_icon.png
- chmod 644 /Library/Scripts/custom_icon.png
+if [[ -f /Library/Scripts/nice_updater_custom_icon.png ]]; then
+ chown root:wheel /Library/Scripts/nice_updater_custom_icon.png
+ chmod 644 /Library/Scripts/nice_updater_custom_icon.pngg
fi
# Start our LaunchDaemons