Forcing Users to Log Out

slee185
New Contributor

Hey there,

We ask our users to log out every day in order to refresh their network connection and to ensure updates, which we push out on log outs. Unfortunately, we have users who don't ever log out even though we tell them it is required. I would like to create a policy that pushes a pop up on their screen notifying the user they haven't logged out in 24 hours and it is required for them to log out immediately to ensure updates and then only gives them the option to log out there or else they can't use their machine.

If you have any better ideas or suggestions please help me because I know this is blunt but I'm tired of telling them to log out all of the time!!!!

please and thank you

-slee

7 REPLIES 7

alanmcseveney
New Contributor

Which apps are you updating on logout? Have you looked at Auto Update Magic?

If you really need to logout all users, you can always do:

/usr/bin/killall WindowServer || /usr/bin/killall -9 WindowServer

Not pretty, but should work. Equivalent to hitting Ctrl Alt Backspace in Linux.

PeterClarke
Contributor II

I have previously used: /usr/bin/sudo /usr/bin/killall loginwindow

I have not used 'WindowServer' - just tried it and - doesn't work…
but 'loginwindow' does…

dgreening
Valued Contributor II

I've been using this in my FileVault script - it logs the user out gracefully so that they see the FV password prompt.

osascript -e 'tell application "loginwindow" to «event aevtrlgo»'

mm2270
Legendary Contributor III

I have used the same code as @dgreening's above when I've needed a graceful logout. Only thing is, since its an osascript call, you may need to wrap it in a way that it gets called as the logged in user or the OS may balk and block it from running. Applescript/osascript calls are kind of hit or miss in this regard. Sometimes they work fine and other times they don't. I'm talking about when they are called by the natural Jamf LaunchDaemon check-in process, which runs everything as root.

I would avoid killing the loginwindow if possible. Although it certainly does perform a "logout", keep in mind any open unsaved data will certainly be lost. Apps that support Resume and autosave features may not auto save anything when the login window is killed in that manner. Just something to be aware of.

I can understand the frustration with users not listening to basic instructions. We recommend users reboot their Macs at least once a month, as a simple preventative maintenance step, but we get lots of folks that keep their Macs "up" for many months at a time, and then have the audacity to complain to us that their Mac is slowing down! Well, gee, I wonder why?

hjcao
Contributor

Hey @slee185

Mac users are notorious for not logging out and just letting their machine sleep. I would venture to say even some of us do this at times. =)

Quick question, I saw in your other thread that you force reboot the machines on Saturdays. Besides the obvious connection/drive issues, I was curious to how often you were pushing out updates that it required the user to log out everyday as opposed to running these updates during the forced weekly reboot? As @mm2270 said above, forcing shutdowns can open a Pandora's box of issues with users. In my environment it would never fly because if an exec was to lose some info because of a restart policy...... yikes.

johnworne
New Contributor

To do log out we have used: /usr/bin/sudo /usr/bin/killall loginwindow

regards
john worne

russeller
Contributor III

hey @slee185 this might be overkill, and doesn't do a logout like you originally requested, but rather a restart. You can make your policy trigger at startup instead of logout if you ended up using something like this.

You can adjust this to meet your environments needs. I created a script that is in a policy that is scoped to a smart group based on an extension attribute that tracks how many days that Mac has been 'up' or it's 'uptime'. If it has been over 14 days the Mac will be scoped to this 'everyHour' triggered policy that will prompt the user to 'Reboot Now' or 'Reboot Later'. I use a plist to track the amount of times that have chose 'Reboot Later' and warn them they can only defer the message up to 5 times. On the 6th time it shows them a 5 minute warning to save their work and reboots the computer. I have had this running for about 6 months in a K-12 and the teachers/staff have been really good about rebooting and no one has complained about it (not that I've heard at least). It gives them plenty of time (5 days) to save their work and reboot once they get the first warning. You can shorten this requirement if you'd like.

First, create this script in your JSS and name it sometime like uptime_reboot_reminder or whatever. I broke up the script with comments here so if you'd like use it, I'd download it here and copypasta it into your JSS Link to script here

#!/bin/bash
################################################################################
#
#   Written with love by: Steven Russell / steven_russell at beaverton.k12.or.us
#   Date: 30 Sept 2016
#   Scriptname: uptime_reminder.sh
#
#   Purpose:
#      The purpose of this script is to run when computer joins the "uptime
#      over 14 days" group. It'll run everyHour once per day for the user. It
#      will prompt them to Restart Now, or Restart Later with a 5 time counter.
#      It will explain to them that it is to improve performance and allow it to
#      run updates and security patches.
#
################################################################################

########################### Variables and Functions ############################
### declare variables for uptime check
declare -x awk="/usr/bin/awk"
declare -x sysctl="/usr/sbin/sysctl"
declare -x perl="/usr/bin/perl"
declare -xi DAY=86400
declare -xi EPOCH="$($perl -e "print time")"
declare -xi UPTIME="$($sysctl kern.boottime | $awk -F'[= ,]' '/sec/{print $6;exit}')"
declare -xi DIFF="$(($EPOCH - $UPTIME))"

## Variables
login_username=$(/usr/bin/who | awk '/console/{ print $1 }')
## You should change this to something that matches your company/institution

You'll want to put in whatever value you want in this variable below...

prefs="/Library/Preferences/com.uptime.whatever.configuration"

### Set the jamf binary
jamf_binary=$(/usr/bin/which jamf)
if [[ "$jamf_binary" == "" ]] && [[ -e "/usr/sbin/jamf" ]] && [[ ! -e "/usr/local/bin/jamf" ]]; then
 jamf_binary="/usr/sbin/jamf"
elif [[ "$jamf_binary" == "" ]] && [[ ! -e "/usr/sbin/jamf" ]] && [[ -e "/usr/local/bin/jamf" ]]; then
 jamf_binary="/usr/local/bin/jamf"
elif [[ "$jamf_binary" == "" ]] && [[ -e "/usr/sbin/jamf" ]] && [[ -e "/usr/local/bin/jamf" ]]; then
 jamf_binary="/usr/local/bin/jamf"
fi

### Check the amount of days this Mac has been up
if [ $DIFF -le $DAY ] ; then
        $(defaults write $prefs uptime -int 1)
else
        $(defaults write $prefs uptime -int $(($DIFF / $DAY)))
fi

### Uptime variable
uptime=$(defaults read $prefs uptime)

### Echo out the uptime to the log
echo "Uptime: $uptime Days"

You can customize the amount of deferred days you want here below...

### Define the amount of Days before a forced restart
total_days="5"

## Write to the Configuration Plist the amount of times the pop up as occurred
if [[ ! $(defaults read $prefs uptime_message 2>/dev/null) ]]; then
  defaults write $prefs uptime_message -int 1
fi

amount_of_days=$(defaults read $prefs uptime_message)
if [ "$amount_of_days" = "" ]; then
  defaults write $prefs uptime_message -int 1
  amount_of_days="1"
else
  amount_of_days=$(defaults read $prefs uptime_message)
fi

### jamfHelper
jamfHelperbin="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"
windowType="hud"
title="Name of your Company"
heading="Your Mac hasn’t been restarted for [ $uptime ] days"
description="Your Mac has been on for [ $uptime ] days. Restarting your computer is necessary for better 
performance and to receive critical software and security updates. This is alert [ $amount_of_days of $total_days ] after 
which your computer will automatically restart with only a 5-minute warning. Please take this 
opportunity to save your work in-progress and choose “Restart Now”. Thank you."
button1="Restart Now"
button2="Restart Later"

You can adjust the timeout for the message here below...

timeout="180"
iconpath="/System/Library/CoreServices/File Sync.app/Contents/Resources/Sync Services Icon.icns"


### JAMF Reboot message to be used when/if the user chooses to reboot, hopefully
jamf_reboot_message="Save your work, the computer will restart in 5 
minutes. You can restart immediately by choosing the Apple in the 
top-left corner and selecting 'Restart' from the menu."

################################################################################
### Let's make sure this doesn't run if the Mac has been uptime less than 14 days

Here is a check to ensure this isn't running on a Mac that is shouldn't be

if [ "$uptime" -lt "14" ]; then
  echo "This shouldn't be running, less then 14 days uptime..."
  exit 0
fi

### Let's check the "total_popup_messages" count, if it is null, let's add 1.
check_popup_messages=$(defaults read $prefs uptime_message)
if [[ ! "$check_popup_messages" ]]; then
  total_popup_messages="1"
else
  total_popup_messages="$check_popup_messages"
fi

### Check for the amount of attempts, if equal to or greater then 6, forcing a restart
### with a 5 minute warning for the user to save their work and restart.

You'd change this value below if you wanted to change the deferred days

if [ "$total_popup_messages" -ge "6" ]; then
  ## already have presented the user 5 attempts to restart their computer, forcing restart
  echo "Starting $total_popup_messages Attempt: Forcing restart."
  echo "Rebooting now: Clearing the uptime_message counter..."
  defaults write $prefs uptime_message -int 1
  $jamf_binary reboot -minutes 5 -message "$jamf_reboot_message" -background
  exit 0
fi

You'd also change the value here, as I'm writing this it would have been a lot easier to put this in a variable, you can do that if you'd like

if [ "$total_popup_messages" -le "5" ]; then
  ## already have presented the user 5 attempts to restart their computer, forcing restart
  echo "Starting $total_popup_messages Attempt: Showing Warning..."
  if [ "$total_popup_messages" = "5" ]; then
    heading="FINAL WARNING: Mac hasn't restarted in [ $uptime ] days"
  fi
  ### Start jamfHelper
  jamfMessage=$("$jamfHelperbin" -windowType "$windowType"  -title "$title"  -heading 
  "$heading" -description "$description" -icon "$iconpath" -timeout "$timeout"  
  -button1 "$button1" -button2 "$button2" -defaultButton "2" -lockHUD 2>/dev/null)
fi

#Return Values: The JAMF Helper will print the following return values to stdout...
#   0 - Button 1 was clicked
#   1 - The Jamf Helper was unable to launch
#   2 - Button 2 was clicked
#   3 - Process was started as a launchd task
#   XX1 - Button 1 was clicked with a value of XX seconds selected in the drop-down
#   XX2 - Button 2 was clicked with a value of XX seconds selected in the drop-down
#   239 - The exit button was clicked
#   240 - The "ProductVersion" in sw_vers did not return 10.5.X, 10.6.X or 10.7.X
#   243 - The window timed-out with no buttons on the screen
#   250 - Bad "-windowType"
#   254 - Cancel button was select with delay option present
#   255 - No "-windowType"

#Usage:  jamf reboot [-minutes <minutes>] [-message <message>] [-background] [-immediately]
#    -minutes        The minutes until the machine should reboot
#    -message        The message to display to any logged in users
#    -background         Background this process (don't wait until the reboot to exit)
#    -immediately        Reboot now without warning users

## Case JAMF Helper and add a day to uptime_message plist if user says "Reboot Later"
case $jamfMessage in
  0) echo "User chose Restart Now"
     # reset the uptime_message counter incase it was above 1
     echo "Rebooting now: Clearing the uptime_message counter..."
     defaults write $prefs uptime_message -int 1
     #restart the computer with jamf_binary with 5 min warning
     $jamf_binary reboot -minutes 5 -message "$jamf_reboot_message" -background
     exit 0
  ;;
  2) echo "User chose Restart Later"
     let "amount_of_days=amount_of_days+1"
     defaults write $prefs uptime_message -int $amount_of_days
     #mark the uptime_message value and exit the script successfully
     echo "Added 1 more attempt to uptime_message. We are now at attempt(s): $amount_of_days"
     exit 0
  ;;
  *) echo "Error occred, exiting with error..."
     exit 1
  ;;
esac

### Comments:
# 1.0 - Initial script
# 1.1 - Changed the checking of uptime_message to avoid errors

Next, now that the script has been uploaded to the JSS, we are going to create a 'Computer Extension Attribute' that will run a script that'll tell us the amount of days a Mac has been up. This is how we'll scope the Macs to the Policy that will execute this script. Go to Settings > Computer Management > Extension Attributes and create a new one called "Uptime Days" or whatever you'd like to call it. Populate the Input Type to Script and the "Data Type" to Integer (This is really important).

#!/bin/bash
#SR Sept 2016
# Commands required by this script
declare -x awk="/usr/bin/awk"
declare -x sysctl="/usr/sbin/sysctl"
declare -x perl="/usr/bin/perl"
declare -xi DAY=86400
declare -xi EPOCH="$($perl -e "print time")"
declare -xi UPTIME="$($sysctl kern.boottime | $awk -F'[= ,]' '/sec/{print $6;exit}')"
declare -xi DIFF="$(($EPOCH - $UPTIME))"

#You can customize this below to match your script 
prefs="/Library/Preferences/com.uptime.whatever.configuration"
if [ $DIFF -le $DAY ] ; then
        $(defaults write $prefs uptime -int 1)
else
        $(defaults write $prefs uptime -int $(($DIFF / $DAY)))
fi
echo "<result>$(defaults read $prefs uptime)</result>"

Make sure to update the $prefs variable to match your script

Now, you'll create a new Computer Smart Group that will use the value of "Uptime Days" and set it to 'more than' 14 or however many days you want. If you are changing this value, be sure to update the check in the script to match this value (on line 96)

Finally, you'll simply scope the Policy you created that has the script attached to it to this new Computer Smart Group you created. So something like this:

Policy Name: uptime_reminder [14 days or more]
Scope: uptime_14_plus
Payload: uptime_reminder script
Trigger: Recurring Check-In
Execution Frequency: Once every day

Once the Macs start doing their weekly recon (or however often you recon your Macs) they'll start scoping themselves to the uptime policy and presenting the users their Restart Reminder messages. You can add extra criteria to your uptime_14_plus Smart Group to also limit it to a specific Mac for a testing phase to make sure it all works as expected.