MacBook admins dealing with users who let clock reset due to depleted battery (a contribution)

blackholemac
Valued Contributor III

After coming back from spring break on Monday and finding 5-6 people who left their MacBook Air unplugged and on, I found myself with users who couldn't connect to the 802.1X because of date and time issues. The users do not have admin rights. Nothing like setting the clock manually for people and rebooting.

I decided to try tackling the problem in the form of a script. Said script would be triggered at login on an ongoing basis (in offline mode as the JSS itself may very well be unreachable at that point). It would be scoped to an all MacBooks smart group or any other relevant targets that the admin sees fit.

It would work something like this below. I was actually able to find a file whose date is updated but otherwise not changed by the end user in the form of the XProtect definitions bundle. Any feedback or enhancements are welcome. I've tried it out on a computer by manually setting it's clock backward and it does seem to work. I haven't actually tried it using my JSS though.

Hope this helps someone

#!/bin/bash

REFERENCEDATE=`date -r /System/Library/CoreServices/XProtect.bundle +%Y%m%d`
CURRENTSYSTEMDATE=`date +%Y%m%d`

if [ "$CURRENTSYSTEMDATE" -ge "$REFERENCEDATE" ]
then exit 0
else echo "Going into one-time clock set..."

UserSetDate=$(osascript -e 'tell application "SystemUIServer"
    set myUserSetDate to text returned of (display dialog "The current clock set on your computer is set to " & (current date) & ".

Please consult your nearest functional calendar and insert the date as MM:DD:YY" default answer "" with title "Set the Proper Date" buttons {"Submit"} default button 1 with icon caution)
end tell')

UserSetClock=$(osascript -e 'tell application "SystemUIServer"
    set myUserSetDate to text returned of (display dialog "The current clock set on your computer is set to " & (current date) & ".

Please consult your nearest functional clock and insert the time in military time format as HH:MM:SS. 

2:04 PM would be written as 14:04:00. 
7:30 AM would be written as 07:30:00.

You can guess on the amount of seconds" default answer "" with title "Set the Proper Clock" buttons {"Submit"} default button 1 with icon caution)
end tell')

systemsetup -setusingnetworktime off
systemsetup -setdate $UserSetDate
systemsetup -settime $UserSetClock
shutdown -r NOW
fi
1 ACCEPTED SOLUTION

blackholemac
Valued Contributor III

@boberito i love it and am eager to test! In short I only want it to fire off in extreme situations but what was kicking my butt was the user input error checking...this solves that problem perfectly. I’m marking as solution pending testing, but I love seeing how people can make it better.

View solution in original post

15 REPLIES 15

amoscaritola
New Contributor III

Are you allowed to unlock the Date & Time preferences for standard users?

security authorizationdb write system.preferences allow
security authorizationdb write system.preferences.datetime allow

boberito
Valued Contributor

Why do you have the computer rebooting after setting the date and time?

blackholemac
Valued Contributor III

No to the date and time post we do not want to unlock that for users as time drift of more than three minutes causes problems. Asking about the reboot, that’s a very good question...We handle 802.1X authentication at the login window so At a bare minimum, I will need to force a log out to allow for a proper re-connection to the Wi-Fi, I figured since this user is already being inconvenienced an extra reboot doesn’t hurt

boberito
Valued Contributor

6b0f5eb1e6814169b6bfe9dd502a1c19
I updated your script using pashua dialog. This way users can't really muck up the date and time format.

#!/bin/sh

pashuapath="/usr/local/saes/Pashua.app/Contents/MacOS/Pashua"

pashua_run() {

    # Write config file
    local pashua_configfile=`/usr/bin/mktemp /tmp/pashua_XXXXXXXXX`
    echo "$1" > "$pashua_configfile"

    if [ "" = "$pashuapath" ]
    then
        >&2 echo "Error: Pashua could not be found"
        exit 1
    fi

    # Get result
    local result=$("$pashuapath" "$pashua_configfile")

    # Remove config file
    rm "$pashua_configfile"

    oldIFS="$IFS"
    IFS=$'
'

    # Parse result
    for line in $result
    do
        local name=$(echo $line | sed 's/^([^=]*)=.*$/1/')
        local value=$(echo $line | sed 's/^[^=]*=(.*)$/1/')
        eval $name='$value'
    done

    IFS="$oldIFS"
}

REFERENCEDATE=$(date -r /System/Library/CoreServices/XProtect.bundle +%Y%m%d)
CURRENTSYSTEMDATE=$(date +%Y%m%d)

if [ "$CURRENTSYSTEMDATE" -ge "$REFERENCEDATE" ]; then 
    exit 0
else 
    echo "Going into one-time clock set..."

conf="
# Set window title
*.title = Date and Time
*.floating = 1

img.type = image
img.x = 0
img.y = 125
img.maxwidth = 50
img.maxheight = 50
img.path = /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/AlertNoteIcon.icns

# Message
txt.type = text
txt.default = Your current date and time is incorrect. This will result in problems connecting to the network. 
txt.width = 200
txt.x = 60
txt.y = 110

# Date and time picker
d.type = date
d.label = Please set the Date and Time
d.textual = 1
d.date = 1
d.time = 1
"
    pashua_run "$conf" "$customLocation"

    newmonth=$(echo $d | awk '{ print $1 }' | awk -F "-" '{ print $2 }')
    newday=$(echo $d | awk '{ print $1 }' | awk -F "-" '{ print $3 }')
    newyear=$(echo $d | awk '{ print $1 }' | awk -F "-" '{ print $1 }' | cut -c 3-)
    UserSetDate="$(echo $d | awk '{ print $1 }' | awk -F "-" '{ print $2 }'):$(echo $d | awk '{ print $1 }' | awk -F "-" '{ print $3 }'):$(echo $d | awk '{ print $1 }' | awk -F "-" '{ print $1 }' | cut -c 3-)"
    UserSetClock=$(echo $d | awk '{ print $2 }')

    systemsetup -setusingnetworktime off
    systemsetup -setdate $UserSetDate
    systemsetup -settime $UserSetClock
    shutdown -r NOW
fi

blackholemac
Valued Contributor III

@boberito i love it and am eager to test! In short I only want it to fire off in extreme situations but what was kicking my butt was the user input error checking...this solves that problem perfectly. I’m marking as solution pending testing, but I love seeing how people can make it better.

Stubakka
Contributor II

Does this still work in 10.14.6? Im looking for a solution for this issue also, or is there a better way with a config profile ?

AVmcclint
Honored Contributor

@Stubakka I just tried @boberito's script with Pashua and it works in Catalina. I manually set my system clock to 3 years in the past, then ran it in Terminal (and commented out the shutdown line), but it does appear to work. I do like how this gives users the ability to fix their own clock when they aren't admins.

I would love to figure out how to validate the system clock with a known external clock and then trigger this. The way I read this, it will only trigger if the current date is not newer than the last time the XProtect.bundle file was touched.... which could be many days or weeks in the past. But I guess when the battery is drained and the clock resets, it will be many days or weeks behind. Hmmm.... ya know what, I'll take it. Anything we can do to let users fix their own problems is fine by me! As for daily clock drift, I have the daily inventory policy also run a command to sync with the internal servers.

boberito
Valued Contributor

@AVmcclint The problem with an external clock is that in a lot of environments, you may be connecting to an 802.1x network and that requires the time to be relatively correct to connect. Otherwise if they had a network connection, you could just set the time server with a config profile and it'd update automagically.

I'm also sure there's a better file somewhere you could use to test against.

AVmcclint
Honored Contributor

@boberito I agree. I do applaud you and @blackholemac for your novel ways of addressing the clock reset problem.

GabeShack
Valued Contributor III

@AVmcclint Another reason the XProtect time and date is ok even if its a week old, is usually its not clock skew that's the issue with reconnecting to a 802.x network, its usually about the date on the device being set to a date before the certificate was created, so as long as the date on the XProtect file is after the creation date of the certificate, it should work to get the user connected, and then it would update from the time server after connection, breaking the catch 22.

My solution in the past was 2 launch Daemons that would run to check if the date and time was set before our certificate was created. It would run at restart and sleep with another program called sleepwatcher. My method was much more complicated, so I would not recommend it over this solution, but I'll attach what I was doing in case it helps someone else:
Daemons
Set Date and Time Daemon

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.pps.setdateandtime</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
<key>ProgramArguments</key>
<array>
<string>/Library/PPS/setdateandtime.sh</string>
</array>
</dict>
</plist>

Sleepwatcher daemon

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>de.bernhard-baehr.sleepwatcher</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/sbin/sleepwatcher</string>
        <string>-V</string>
        <string>-s /etc/rc.sleep</string>
        <string>-w /Library/PPS/setdateandtime.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
</dict>
</plist>

Set Date and time Script (can be set to any date and time as long as its after the 802.11x certificate date)

#!/bin/bash
macdate=$(date +"%Y%m%d")
#set to the day of the 802.11x certificate creation date
comparison="20150101"
if [ $comparison -ge $macdate ]; then
#sets to a day after the comparison above
date 0102010115
#turns wifi off then on again to reconnect to top network
networksetup -setairportpower en1 off
networksetup -setairportpower en1 on
#waits for connection
sleep 15
#sets the actual date and time from time server of your choice or apple
ntpdate -u time.apple.com
fi

link to sleepwatcher

Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

Stubakka
Contributor II

@boberito When I try to run your version via Self service , get this error, Both on a 10.14.6 and 10.15.5 system , any ideas? 28869412f8cb47719df21a7e5d0eb7ba

boberito
Valued Contributor

@Stubakka remove line 4.

Tangentism
Contributor II

@bobertio I was going to ask what that line did!

boberito
Valued Contributor

The jamf board somehow added it. I'm not sure why or whatever but that's the way you link to an image or something you've attached. I edited the post with the script and removed it.

echave
New Contributor III

For anyone using @boberito's script, the original file being used to get a reference date is an alias/symlink that no longer exists as of 11.3. Change

REFERENCEDATE=$(date -r /System/Library/CoreServices/XProtect.bundle +%Y%m%d)

To

REFERENCEDATE=$(date -r /Library/Apple/System/Library/CoreServices/XProtect.bundle +%Y%m%d)