I need a a way to automatically log out users

emadams
New Contributor III

I have a large number of labs in our district and students will either walk away from their workstations at the end of class and rely on another student switch users or just lock their account and leave.  Both scenarios leave the student logged in.  This can create some issues when attempting to use remote commands so I am looking for a configuration or script that I can deploy that will log users out.  I would think the easiest way to do this is deploy something at the end of the day.  Just wondering if anyone has something they are using that they like.

1 ACCEPTED SOLUTION

PaulHazelden
Valued Contributor

I run a pair of scripts, they are launched by a pair of Launch Daemons.
One will attempt to force log out any user account on the Mac at a set time, thus allowing my power management settings to shut the Mac down. But this can hit problems when the user leaves unsaved work open.
The second is a bit more draconian. It will shut the Mac down at a set time, regardless of work saved or not.
These are the bits of the script that do the work, I have logging in place so I can check on things later if i need to.
Logout script does this...

CURRUSER=$(/usr/bin/who | /usr/bin/grep console | /usr/bin/head -n 1 | /usr/bin/awk '{print $1}')
    # Kill the login session
    /bin/kill `ps uaxww | grep $CURRUSER | grep loginwindow | awk '{print $2}'`

The Hard Shutdown script has this added to it after the kill...

shutdown -h now

The LaunchDaemon for the first script is...

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>com.UNIQUE.NAME.FOR.DAEMON</string>
	<key>ProgramArguments</key>
	<array>
		<string>/Path/to/script/shutdown.sh</string>
		<string>-argument</string>
	</array>
	<key>StartCalendarInterval</key>
	<dict>
		<key>Hour</key>
		<integer>20</integer>
		<key>Minute</key>
		<integer>55</integer>
	</dict>
</dict>
</plist>

And the Hard ShutdownDaemon is...

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>com.UNIQUE.NAME.FOR.DAEMON</string>
	<key>ProgramArguments</key>
	<array>
		<string>/PATH/TO/SCRIPT/shutdownhard.sh</string>
		<string>-argument</string>
	</array>
	<key>StartCalendarInterval</key>
	<dict>
		<key>Hour</key>
		<integer>21</integer>
		<key>Minute</key>
		<integer>15</integer>
	</dict>
</dict>
</plist>

You will need to put in a Unique name for the LaunchDaemons, and the correct Path to your scripts. You will also note I have the Logout run at 20:30 daily and the Hard shutdown at 21:15, My power settings are set to shutdown at 21:00 daily.
As these are LaunchDaemons they are set to run at every boot, and the Power management settings are used for the most part to shut the Macs down in a nice way.
In addition I do have a loginwindow profile that includes the Log out after 30 mins of inactivity, but this does not always work because they can leave unsaved work open.
As with all scripts, please test, test and test again before putting into production.


View solution in original post

12 REPLIES 12

mattjerome
New Contributor III

If you're using something Jamf Connect, you can set this up. That's probably the easiest way.

emadams
New Contributor III

@mattjerome Is there a list of configurations for a plist upload somewhere?  I am assuming that would be how to accomplish that using Jamf Connect.

mattjerome
New Contributor III

_gsm
New Contributor III

You can use a login window configuration profile. 

 

Screenshot 2024-10-28 at 2.53.32 PM.png

AJPinto
Honored Contributor III

In addition to the login window payload to log users out after XYZ inactivity, I recommend a daily reboot also.

emadams
New Contributor III

Yeah, I have that in place now but with mixed results.  If I have a lab of 40 workstations, I can get about 2/3 of them to restart properly.  Hence the need to see if logged in users is one of the reasons for this.

PaulHazelden
Valued Contributor

I run a pair of scripts, they are launched by a pair of Launch Daemons.
One will attempt to force log out any user account on the Mac at a set time, thus allowing my power management settings to shut the Mac down. But this can hit problems when the user leaves unsaved work open.
The second is a bit more draconian. It will shut the Mac down at a set time, regardless of work saved or not.
These are the bits of the script that do the work, I have logging in place so I can check on things later if i need to.
Logout script does this...

CURRUSER=$(/usr/bin/who | /usr/bin/grep console | /usr/bin/head -n 1 | /usr/bin/awk '{print $1}')
    # Kill the login session
    /bin/kill `ps uaxww | grep $CURRUSER | grep loginwindow | awk '{print $2}'`

The Hard Shutdown script has this added to it after the kill...

shutdown -h now

The LaunchDaemon for the first script is...

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>com.UNIQUE.NAME.FOR.DAEMON</string>
	<key>ProgramArguments</key>
	<array>
		<string>/Path/to/script/shutdown.sh</string>
		<string>-argument</string>
	</array>
	<key>StartCalendarInterval</key>
	<dict>
		<key>Hour</key>
		<integer>20</integer>
		<key>Minute</key>
		<integer>55</integer>
	</dict>
</dict>
</plist>

And the Hard ShutdownDaemon is...

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>com.UNIQUE.NAME.FOR.DAEMON</string>
	<key>ProgramArguments</key>
	<array>
		<string>/PATH/TO/SCRIPT/shutdownhard.sh</string>
		<string>-argument</string>
	</array>
	<key>StartCalendarInterval</key>
	<dict>
		<key>Hour</key>
		<integer>21</integer>
		<key>Minute</key>
		<integer>15</integer>
	</dict>
</dict>
</plist>

You will need to put in a Unique name for the LaunchDaemons, and the correct Path to your scripts. You will also note I have the Logout run at 20:30 daily and the Hard shutdown at 21:15, My power settings are set to shutdown at 21:00 daily.
As these are LaunchDaemons they are set to run at every boot, and the Power management settings are used for the most part to shut the Macs down in a nice way.
In addition I do have a loginwindow profile that includes the Log out after 30 mins of inactivity, but this does not always work because they can leave unsaved work open.
As with all scripts, please test, test and test again before putting into production.


emadams
New Contributor III

Thank you for the information.  I am still learning how to use Daemons so I will play with this and see if I can get it to work properly. 

LaunchDaemons run at boot. If they run a script it will be done as the root user. They can't interact with the GUI, because chances are when they run there is no user logged in.
LaunchAgents run at Login, if they run a script it will be done as the logging in user. These can interact with the GUI, because there is a user logging in.

They are both fussy about the permissions for themselves and for scripts they run.
LaunchAgents permissions should be 644 and any script they run should be 755
LaunchDaemons permissions should be 644 and any script they run should be 700

With both you need a unique name for the process, that goes in the plist.

emadams
New Contributor III

Looking at the script for logging out the user, doesn't 

CURRUSER

only going to grab the current user still logged in?  What if there are multiple users that have not properly logged out of the workstation.  This is a student lab environment so there is a really good chance that two or three students may be logged into a workstation.

 

We dont have Fast user switching on, so we only have one user logged in at a time. Sorry, I have never looked into that situation. The hard shutdown will still work.

You can try switching to the users command rather than the who one. I dont have a mac to test it on with multiple accounts logged in, but the users command is supposed to show all logged in users.
I would then use a for loop to run through each one at a time.

CURRUSER=$(users)
for eachuser in $CURRUSER
do

    # Kill the login session
    /bin/kill `ps uaxww | grep $eachuser | grep loginwindow | awk '{print $2}'`
done

I have not tested that script, I just wrote it on the fly, so please test it out first,

emadams
New Contributor III

Okay, that makes sense.  I took your script and worked it a bit more.

# List all logged-in users and exclude "root" and "console" users
loggedInUsers=$(who | awk '{print $1}' | sort | uniq | grep -v -e '^root$' -e '^console$')

# Loop through each user and log them out
for user in $loggedInUsers; do
    echo "Logging out user: $user"
    pkill -KILL -u "$user"
done

echo "All users have been logged out."

# Reboot the system
shutdown -r now

I added a reboot at the end just for good measure.  I have tested a couple of time with a policy and it seems to work.  I even tested with a user logged in and an unsaved word document and it logged out both accounts and rebooted the workstation.