Posted on 01-15-2013 05:11 AM
Hi there,
I'm trying to check in a script if the screen of a user is locked. I don't want to display a message with jamfhelper while the screen is locked so other users could click the buttons of the message (for example installing software updates with reboot).
One attempt is to use something like this:
import Quartz; d=Quartz.CGSessionCopyCurrentDictionary(); print d
(source: http://stackoverflow.com/questions/11505255/osx-check-if-the-screen-is-locked)
This works when testing on a local machine but does not work with ssh or policies. I only get back "None" as a result when using it with SSH or Policies.
The other possibility i found is to check if the screensaver process is running. But this does not work when the display is going off because then the screensaver process stops too and the message is displayed immediately after revoking the display.
Does anyone has a working solution to check if the screen is locked?
Thanks.
Solved! Go to Solution.
Posted on 01-15-2013 07:21 AM
Do you have all your Macs set to lock the screen after a certain amount of idle time, such as after 5 or 10 minutes? Is it being managed so users cannot change that setting?
If so, you may be able to check the current idle time on the Mac with ioreg and, if its beyond the threshold you've set, you can assume the Mac's screen is locked.
HTH somewhat.
Posted on 01-16-2013 12:34 AM
Thanks for all the answers.
With your answers I created now a script that checks both, idle time and the screensaver process, in a loop. It fits my needs and seems to take care of all or at least most possible conditions. (Screensaver is started with hot corner, Screensaver starts after some idle time, Display is off after some more idle time...)
As our screensaver settings are set with MCX I don't need to check the idle time from com.apple.screensaver.plist until the screensaver starts.
This is the script I used for testing (only tested with 10.8.2) . Perhaps it helps some others too. I'm not sure if my code is clean and state of the art. ;-)
#!/bin/bash
# Check if screensaver is running or the system is idle for 5 minutes or more (locked)
IDLECOUNT=1
SCREENSAVER=1
while [ $IDLECOUNT != "0" ] || [ $SCREENSAVER != "0" ]; do
sleep 5
IDLETIME=$((`ioreg -c IOHIDSystem | sed -e '/HIDIdleTime/ !{ d' -e 't' -e '}' -e 's/.* = //g' -e 'q'` / 1000000000))
echo Idle Time is $IDLETIME
if [ "$IDLETIME" -gt "299" ]; then
echo "User is away."
IDLECOUNT=1
else
echo "User is working."
IDLECOUNT=0
fi
ps ax|grep [S]creenSaverEngine > /dev/null
if [ "$?" != "0" ] ; then
echo "Screensaver is disabled."
SCREENSAVER=0
else
echo "Screensaver is enabled."
SCREENSAVER=1
fi
done
echo "Display is unlocked!"
Posted on 01-15-2013 07:21 AM
Do you have all your Macs set to lock the screen after a certain amount of idle time, such as after 5 or 10 minutes? Is it being managed so users cannot change that setting?
If so, you may be able to check the current idle time on the Mac with ioreg and, if its beyond the threshold you've set, you can assume the Mac's screen is locked.
HTH somewhat.
Posted on 01-15-2013 07:49 AM
Hello Mike,
That's a good idea. Thank you. :)
I think I can script something useable with that.
Most users should have a locked screen after 5 minutes.
Regards
Posted on 01-15-2013 08:03 AM
Sure, glad that helped a bit. However, after I posted that, I realized that one scenario where this may fail is if a user manually locks their screen using the Keychain menu. I lock my screen religiously for security reasons when i walk away from my Mac. But at that point, the idle time on my Mac is actually well below the threshold for when it would lock automatically. If a script was checking to see if the idle time was under 5 minutes or so, it would end up showing that jamfHelper dialog. Just something to be aware of.
I'm not sure how else you'd really get that information though. I looked at the link you provided and the command, but I can't actually get it to work, so I'm not sure what it outputs. In that thread further down the OP suggests using another 'ioreg' command to get the screen lock status, but doesn't really elaborate. Maybe something else to explore as well.
Posted on 01-15-2013 12:58 PM
Could you check to see if the 'screensaver' process is running? Pretty sure that's what it's called. Toss a system into screen saver, SSH into it and check out the process table. Should be a cinch.
EDIT: The process you're looking for (on 10.8 anyway) is 'ScreenSaverEngine'
Posted on 01-15-2013 01:14 PM
In addition to looking for ScreenSaverEngine, to check to see if it will lock, you can take a peek at:
mbp:~ admin$ defaults read com.apple.screensaver
{
askForPassword = 1;
askForPasswordDelay = 5;
}
Posted on 01-15-2013 02:02 PM
It just so happens I wrote a script to cover this:
loggedInUser=`who | grep console | awk '{print $1}'`
IsAdmin=`dseditgroup -o checkmember -m $loggedInUser admin | awk '{print $1}'`
if [ "$loggedInUser" == "" ]; then ## if no one is logged in the screen will not lock on idle, so exit
echo "No one is logged in."
exit
elif [ "$loggedInUser" != "" -a "$IsAdmin" == "yes" -a "$loggedInUser" != "localadmin" ]; then ## if the user is an admin other than localadmin, the unlock
won't work and we do not want to risk leaving up the localadmin account information for everyone to see.
echo "$loggedInUser is an admin (not localadmin). Cannot unlock the screen. Exiting."
exit
else
## The following is a multi-line Applescript to verify system idle time and unlock the screen if necessary, called from the shell via osascript using the
HEREDOC method. This preserves all Applescript line breaks and quoting within bash since Applescript is necessary to simulate user input. It reads all text
between the <<ENDDetectUnlock and ENDDetectUnlock entries into osascript and executes them as Applescript commands.
osascript<<ENDDetectUnlock
set unlockAfter to 1202 -- The desktop is set to lock after 20 minutes of inactivity, however if the mouse is moved or keyboard pressed immediately
after the screen saver starts, the Mac will NOT prompt for a password, so set the locked desktop check to 20 minutes and 2 seconds (1202 seconds)
tell application "System Events" to set screenSaverActive to (exists process "ScreenSaverEngine") -- the user may have their screen saver start before
the system is idle for 20 minutes which will also lock the computer, so we need to check for this as well, since the system may not be idle for ~20.033
minutes yet
set idleTime to do shell script "echo $((`ioreg -c IOHIDSystem | sed -e '/HIDIdleTime/ !{ d' -e 't' -e '}' -e 's/.* = //g' -e 'q'` / 1000000000))"
-- get the system idle time in seconds
if ((idleTime as integer) ? unlockAfter) or screenSaverActive then
Full article here:http://acdesigntech.wordpress.com/2012/02/03/using-bash-and-applescript-to-unlock-a-macs-desktop/
Obviously that's not the whole script, but the key element here is this line:
set idleTime to do shell script "echo $((`ioreg -c IOHIDSystem | sed -e '/HIDIdleTime/ !{ d' -e 't' -e '}' -e 's/.* = //g' -e 'q'` / 1000000000))"
The will get you the system idle time.
Posted on 01-16-2013 12:34 AM
Thanks for all the answers.
With your answers I created now a script that checks both, idle time and the screensaver process, in a loop. It fits my needs and seems to take care of all or at least most possible conditions. (Screensaver is started with hot corner, Screensaver starts after some idle time, Display is off after some more idle time...)
As our screensaver settings are set with MCX I don't need to check the idle time from com.apple.screensaver.plist until the screensaver starts.
This is the script I used for testing (only tested with 10.8.2) . Perhaps it helps some others too. I'm not sure if my code is clean and state of the art. ;-)
#!/bin/bash
# Check if screensaver is running or the system is idle for 5 minutes or more (locked)
IDLECOUNT=1
SCREENSAVER=1
while [ $IDLECOUNT != "0" ] || [ $SCREENSAVER != "0" ]; do
sleep 5
IDLETIME=$((`ioreg -c IOHIDSystem | sed -e '/HIDIdleTime/ !{ d' -e 't' -e '}' -e 's/.* = //g' -e 'q'` / 1000000000))
echo Idle Time is $IDLETIME
if [ "$IDLETIME" -gt "299" ]; then
echo "User is away."
IDLECOUNT=1
else
echo "User is working."
IDLECOUNT=0
fi
ps ax|grep [S]creenSaverEngine > /dev/null
if [ "$?" != "0" ] ; then
echo "Screensaver is disabled."
SCREENSAVER=0
else
echo "Screensaver is enabled."
SCREENSAVER=1
fi
done
echo "Display is unlocked!"
Posted on 01-18-2013 03:40 PM
Pull up a chair my young padawan. :D
This works and much of the time that is good enough. But if you are going to put this on a lot of systems we can clean it up a bit.
+ This is kind of style thing but it also makes things safer. Don't capitalize your variables. You could accidentally step on a system variable someday doing this and depending on what you are doing that could have dire consequences.
+ Good use of || that can be quite handy in many places! Keep playing with it.
+ If you are going to use bash and not sh use [[ instead of [. It is safer and has more features!
+ You don't need to check the exit status of grep in your ps ax | grep statement, just use it directly and quietly with the -q option! Like here:
https://jamfnation.jamfsoftware.com/discussion.html?id=2595
#!/bin/bash
if dscl . read /Users/root | grep -q AuthenticationAuthority; then
echo "<return>Enabled</return>"
else
echo "<return>Disabled</return>"
fi
+ If you are only writing for 10.8.x+ then use the proper tools that Apple has finally graced us with! pgrep & pkill
Finally, here is a cleaner version.
#!/bin/bash
idle_time=$(ioreg -c IOHIDSystem | awk '/HIDIdleTime/ {print int($NF/1000000000); exit}')
# if the screensaver is running then we don't need to check the
# idle_time because we already know we don't want to display anything
if pgrep -q ScreenSaverEngine; then
echo "ScreenSaverEngine is running."
elif [[ "${idle_time}" > 299 ]]; then
echo "idle_time is 5 minutes."
else
echo "The display is unlocked."
fi
The only other thing I would add is to run it via a launchd item instead of a constant while loop.
<?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.foo.bar</string>
<key>ProgramArguments</key>
<array>
<string>/usr/sbin/lock_checker.bash</string>
</array>
<key>StartInterval</key>
<integer>300</integer>
</dict>
</plist>
Cheers,
~Ryan
P.S. The sed version of the oft copied idletime checker is impossible for normal human beings to read. So I copied the awk version
P.P.S. my own comments in the script just made me realize that it could be tweaked a bit so that you don't even burn cycles setting $idle_time unless the ScreenSaverEngine is NOT running but...smeh
Posted on 03-06-2014 08:29 PM
Suggestion:
Assuming System Preferences/Security & Privacy/General/'Require password immediately after sleep or screen saver beings' setting is ENABLED. The lock screen should now have a dependency on the screen saver process being started and the display going to sleep.
Detect screen saver app process:
ps ax|grep [S]creenSaverEngine.app > /dev/null
screen_saver_status=$?
echo $screen_saver_status
#If output is 0, screen saver started.
Detect if display is in sleep mode:
pmset -g activity|awk '/IODisplayWrangler/{getline; print}'|cut -c19
#If output is 4 = display is active
#If output is 3 = display is dimmed, in preparation to go to sleep
#If output is 2 (can also assume 1 and 0) = display is in sleep mode