Mac OS X,  Mac Security,  Mass Deployment

Scripting the Force Log Out

Scripting a log out event seems like the kind of thing that would be pretty simple, and if you use the AppleScript later it does appear simple, unless you want to force the event to occur immediately. Why would we want to do such a thing? Most commonly there are two requests. One is to invoke the script with the screen saver to meet some form of policy that requires a log out after a certain amount of time whether the user has saved their data or not (seems a big mean, but it’s not unheard of). The second is to invoke the script as part of a deployment or as a postflight script. You can force the system to shut down by running the shutdown command with the -h option specified as now as you can see here:

shutdown -h now

You can also restart a system by running the shutdown command with a -r option and the same now as before, as follows:

shutdown -r now

You can also replace the now with a specific time and date to set the system to shut down and/or restart in the future. But these don’t log the system out and leave you at a login window without first actually rebooting a computer we might not be ready to reboot (or we might not want to reboot/shut down). One way to get close is to use the options we referenced yesterday to invoke fast user switching. But it’s one of those things that there’s no real framework for at this time. Again, there is close. You can use AppleScript, but it’s going to ask the user to log out

tell application “System Events” to log out

You can then send this through the shell using osascript:

osascript ‘tell application “System Events” to log out’

Once the screen comes up you could send a subsequent command to click on the Log Out button. However, this can be cancelled by a screen that can’t be closed or a file that needs to be saved (which is by design given that you don’t typically want to risk loosing work) or because an application is unresponsive. We could quit all the open applications using a loop, such as the one I use in the hide all apps application, but then we would need to determine logic on how to answer certain questions that could come up. It was suggested to use killall with the -u option to kill all processes for our current user:

killall -u cedge

But that introduced a little loginwindow instability. So maybe we could just kill loginwindow for the user. To do so we first need to get the pid for loginwindow:

ps -Axjc | grep loginwindow | cut -c 13-16

Once we have that, we can feed it to kill:

kill -9 `ps -Axjc | grep loginwindow | cut -c 13-16`

Which can then be sent through AppleScript as:

tell application “Finder”

do shell scriptkill -9 `ps -Axjc | grep loginwindow | cut -c 13-16`

end tell

Now that it can be done through bash and AppleScript you have a variety of ways to run it against a client system. It’s not as clean as I’d like (throws a few errors in the logs and seems like a hack), so perhaps there’s a better way…