MacOS – How to script the forced logging out another desktop user from OS X

applescriptdesktopmacos

We're running tests that require multiple desktops on a Mac Mini.

We're successfully using an ssh TCP tunnel to localhost, 5900 to 6900, to make Screen Sharing let us log into other users on this same machine with vnc://user:password@localhost:6900 and some Applescript to press the resulting dialogue buttons. I can detect successful login via ssh running a program under Java 1.7 with export AWT_TOOLKIT=CToolkit that tries to open an AWT window as the secondary user, which fails if the desktop isn't started.

This is fairly reliable, although I'd happily hear of more reliable methods!

Where things are going wrong:

We're having problems logging those robot users out, to leave the machine fresh for other tests that object to all the memory wasted by stray processes the users leave running.

I'm currently using

for i in $users ; do
  ssh ${i}@localhost "osascript -e 'tell application \"System Events\"'
                                  -e 'log out'
                                  -e 'delay 3'
                                  -e 'keystroke return'
                                -e end" &
done; wait

but sometimes System Events apparently isn't running and refuses to start:

33:40: execution error: System Events got an error: Application isn’t running. (-600)

I've recently added -e 'if it is not running then launch' -e 'delay 5' immediately before the -e 'log out' but that doesn't seem to do a whole lot to help.

I thought replacing all that Applescript stuff with some variant of ssh kill -KILL -1 would work – at least as a back-up for the hold-out users whose System Events are broken – but it leaves a good couple of dozens of CoreServices, PrivateFrameworks, and Frameworks GUI-looking things running most of which refuse to die even with kill -9 manually aimed at their PIDs. I tried quite hard with a two-stage script, catching the output of killall -s to a file and squirting it into a second ssh session.

Is there a more reliable way to log these users out and kill all their processes? I have admin rights on the box, but I'd prefer something on the Unix command-line to avoid writing further painful AppleScript to manipulate the GUI.

Thanks!

Best Answer

I found what looks like a workable route, but it's indelicate:

Kill the 'loginwindow' process for a user (as root - the user can't kill its own process(!)) (note, the [n] prevents the regex matching itself), then use kill -9 -1 to catch the remaining mess:

    $ for i in $users; do
       echo $pword |
       ssh $i@localhost '
         sudo -S kill -9 $(
           ps -axf | awk "/^ *$(id -u '$i') .*logi[n]window/{ print \$2 }"
         );
         kill -9 -1
       ';
      done

It leaves two processes around

  • /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Versions/A/Support/mdworker -s mdworker -c MDSImporterWorker -m com.apple.mdworker.shared
  • /usr/sbin/cfprefsd agent

...which various mac pages claim are normal OS X weirdness.

I don't particularly like this solution, because it's so abrupt and I'm concerned about leaving things like iOS phone simulators or other files in inconsistent states, but the the absence of another answer, it seems I have little other choice.

At least I can use this as an emergency back-up for when the Applescript route fails, and the kill -9 -1 tidies up what Apple's normal but shoddy logout process leaves hanging around anyway.

I'll also note that doing anything with multiple desktop users messes up network connectivity for me, apparently due to Apple not bothering to think through how authenticated networks should behave.