Jump to content

Getting Another User's Idle Time?


Recommended Posts

So, here's my problem: My script is running as Windows service and must every second or so get idle time of a specific user logged on via Remote Desktop.

I didn't have any problem getting current user's idle time (in this case, the "current user" is SYSTEM), however I found getting another user's idle time to be very difficult.

I imagine one way would be to write output of "query user" to a file and read from it, but I'd really like to avoid unnecessary writing on disk. Another way would be to run a separate script in each user's context and program it to report idle time back to the main script. I don't like this option too - too messy, too many unnecessary processes running.

I found this interesting and 90% undocumented function named WinStationQueryInformationW. Here someone got the results I want from it, but it's written in C... I tried to "translate" that into AutoIT language, but I don't really have enough knownledge in this area.

Is there anybody out there who could help me to make use of that function? I'm also looking for alternatives...

Link to comment
Share on other sites

If this helps anyone, I'm currently using the code below to get the results from "query user" into array. Tested on English versions of Windows 2003 Server Standard SP2, Windows Server 2008 Enterprise R2, Windows 7.

#include <Constants.au3>
#include <Array.au3>
Opt("MustDeclareVars", 1)
Local $users = _QueryUser()
If Not @error Then
_ArrayDisplay($users)
Else
MsgBox(48, 'Error', $users)
EndIf

Func _QueryUser()
Local $line, $lines, $return
Local $runPID = Run(@ComSpec & " /c query useur", @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
Do
  $line = StdoutRead($runPID)
  If $line Then $lines &= $line
Until @error
If $lines Then
  $lines = StringSplit(StringTrimRight(StringReplace(StringRegExpReplace($lines, "(rn)|r|n|(nr)", "|"), ">", ""),1), "|")
  Local $data[$lines[0]][6]
  ;Field lengths: (1+)22, 19, 4, 8, 11, the rest
  For $i = 0 To $lines[0]-1 Step 1
   StringStripWS($lines[$i+1], 3)
   $data[$i][0] = StringStripWS(StringLeft($lines[$i+1], 22), 3)
   $data[$i][1] = StringStripWS(StringLeft(StringTrimLeft($lines[$i+1], 22), 19), 3)
   $data[$i][2] = StringStripWS(StringLeft(StringTrimLeft($lines[$i+1], 22+19), 4), 3)
   $data[$i][3] = StringStripWS(StringLeft(StringTrimLeft($lines[$i+1], 22+19+4), 8), 3)
   $data[$i][4] = StringStripWS(StringLeft(StringTrimLeft($lines[$i+1], 22+19+4+8), 11), 3)
   $data[$i][5] = StringStripWS(StringTrimLeft($lines[$i+1], 22+19+4+8+11), 3)
  Next
  $return = $data
  SetError(0)
Else
  Do
   $line = StderrRead($runPID)
   If $line Then $lines &= $line
  Until @error
  $return = String($lines)
  SetError(1)
EndIf
Return($return)
EndFunc

This code is far from ideal, and I'm still looking for a better way to get this information, especially user's idle time.

Edit: made the code more pretty ;)

Edited by hamster
Link to comment
Share on other sites

  • 5 months later...

Do you know a way that is compatible with Windows XP and Windows 7?

And indeed this methode is far from ideal but can't find an other solution to.

Now I am looking at using the SCCM client. In the file pwrmgmt.log located in C:\Windows\System32\CCM or C:WINDOWSSYSWOW64CCM you can read the power state of the monitor.

In combination with a WMI query to see if there is an active task ending with .scr (screensaver) you can say for sure a pc isn't used. What I do is save the state in a SQlite database, the lib I use is ahkDBA. But using AutoIt you don't need this. Autoit can write to a SQlite database itself without help. Only include this:

#include <SQLite.au3>

#include <SQLite.dll.au3>

In AutoHotKey you need ahkDBA lib from IsNull.

If the computer stays in that state for at least 40 minutes I send a shutdown command.

The WMI query you can rip out of this VBS script: http://webcache.googleusercontent.com/search?q=cache:sFx_rTsSuFEJ:www.visualbasicscript.com/Power-Off-Unused-PCs-m73824.aspx+&cd=1&hl=nl&ct=clnk&gl=nl

Also I check if there isn't an installer running.

Edited by bshogeman
Link to comment
Share on other sites

  • Moderators

That vbscript seems kind of long for just monitoring for screensaver. You could do something like this:

$pc = "<computername>"
$oWMI = ObjGet("winmgmts:" & $pc & "rootcimv2")
$oEventSource = $oWMI.ExecNotificationQuery("SELECT * FROM __InstanceOperationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32_Process'")

While 1
    $oEventObject = $oEventSource.NextEvent()
        If StringRight($oEventObject.TargetInstance.Name, 4) = ".scr" Then
          $aItems = $oWMI.ExecQuery("Select * from Win32_OperatingSystem")
             For $element in $aItems
               $element.Win32Shutdown(4)
             Next
        EndIf
WEnd

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...