Jump to content
Sign in to follow this  
hamster

Getting Another User's Idle Time?

Recommended Posts

hamster

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...

Share this post


Link to post
Share on other sites
hamster

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

Share this post


Link to post
Share on other sites
bshogeman

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

Share this post


Link to post
Share on other sites
JLogan3o13

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

√-1 2^3 ∑ π, and it was delicious!

Share this post


Link to post
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
Sign in to follow this  

  • Similar Content

    • paullauze
      By paullauze
      This function to set Terminal Service information that i wrote a few years ago (with water's help), always worked in Windows XP, but no longer seems to work now that we changes over to Windows 7 machines. all other AD functions seem to work fine. could there be something missing in windows 7 like a .dll or something?
      Func _AD_SetTSProfile($sAD_User)
       If Not _AD_ObjectExists($sAD_User) Then Return SetError(1, 0, 0)
       Local $ID = $sAD_User
       If StringMid($sAD_User, 3, 1) <> "=" Then $sAD_User = _AD_SamAccountNameToFQDN($sAD_User) ; sAMACccountName provided

       $oAD_User.TerminalServicesProfilePath = "Servertsprofiles" & $ID
       $oAD_User.TerminalServicesHomeDirectory = "Servertshome" & $ID
       $oAD_User.TerminalServicesHomeDrive = "Z:"
       $oAD_User.AllowLogon = True
       $oAD_User.SetInfo()
       If @error <> 0 Then Return SetError(@error, 0, 0)
       Return 1
      EndFunc   ;==>_AD_SetTSProfile
      -----------------------------------------------------------------------------------------
      i ran this small script for the purpose of troubleshooting
      #Include <AD.au3>
      #Include <lauze.au3>
      $sAD_User = "TestUser"
       _AD_Open("","","DC=XXX,DC=XXX","Server.XXX.XXX","CN=Configuration,DC=XXX,DC=XXX")
       $result = _AD_SetTSProfile($sAD_User)
       ConsoleWrite("   " & $result & "  - " &  @error & "  -  ")
       _AD_Close()
       
      ----------------------------------------------------------
      results:
      >Running:(3.3.8.1):C:Program Files (x86)AutoIt3autoit3.exe "P:DocumentsAuto Ittestts_win7.au3"   
      --> Press Ctrl+Alt+F5 to Restart or Ctrl+Break to Stop
         0  - -2147352570  -  +>14:02:37 AutoIt3.exe ended.rc:0
      >Exit code: 0    Time: 0.820
       
×