Jump to content
timmy2

Is there a function or API call to detect system is at logon screen?

Recommended Posts

timmy2

My script is run by Task Scheduler at night. I want to leave a message for the user so he can see it the next day.  For users who remained logged in it's easy to leave a message on the screen, but that's impossible when the user is logged off when my task is run (my scripts runs fine; but no messages are displayed.  Is this due to something called "Session 0 Isolation"?)

Is there a sure-fire way to detect if the system is sitting at the logon screen when my script is run by Task Scheduler?

If my script knows it is running while the system is in this state it'll know what activities are impossible, like keyboard/mouse input, displaying messages, etc.

(note Task Scheduler employs the user's credentials to run my script so checking for @username is of no help.)

 

Edited by timmy2

Share this post


Link to post
Share on other sites
JohnOne

Under what account is your script ran when a user is logged off, I'm just a little confused you see.

If I'm correct it's either a normal process which runs under a user account or a service process that runs under the system account.

If It's ran under a user account and that user is logged off, then the task will probably not run at all.


AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Share this post


Link to post
Share on other sites
UEZ

You can use WMI to detect logged in users:

#include "Array.au3"

Opt("MustDeclareVars", 1)
Opt("TrayIconDebug", 1)
Opt("TrayAutoPause", 0)
Global $_nice_COMerrorArray, $_nice_COMerrorObj
_nice_COMerrorHandler(1) ; COM error handler.

ToolTip("mouse over the trayicon for debug info.", @DesktopWidth - 30, @DesktopHeight - 130, "ScriptOMatic - Win32_LoggedOnUser", 1, 4)

Local $a = _WMI_Win32_LoggedOnUser()
If @error Then
    MsgBox(262144, "WMI Output", "No WMI Objects Found for class: " & "Win32_LoggedOnUser")
Else
    Switch @extended
        Case 0
            ToolTip("Done.", @DesktopWidth - 30, @DesktopHeight - 130, "ScriptOMatic - Win32_LoggedOnUser", 1, 4)
        Case 1
            ToolTip("Nothing, you've got nothing." & @CR & @CR & "Adjust the query", @DesktopWidth - 30, @DesktopHeight - 130, "ScriptOMatic - Win32_LoggedOnUser", 2, 4)
        Case 2
            ToolTip("More than you can chew." & @CR & @CR & "Adjust the ""$iLimit"" or the query", @DesktopWidth - 30, @DesktopHeight - 130, "ScriptOMatic - Win32_LoggedOnUser", 2, 4)
    EndSwitch
    If $_nice_COMerrorArray[0][0] Then _nice_COMerrorHandler(2)
    _ArrayDisplay($a, "ScriptOMatic - ""Win32_LoggedOnUser""")
EndIf


Func _WMI_Win32_LoggedOnUser($iLimit = 1000, $sComputer = ".", $sUser = "", $sPassword = "")

    ; Generated by AutoIt ScriptOMatic

    ; Description: The Win32_LoggedOnUser association represents the relationship between a session and the user account using that session.
    ;         Although the association will usually be one to one - users are possible that involve more than one session.
    ;         At the termination of the session the association instance is deleted.


    ; Class Methods:
    ;
    ; ( this Class did not list methods )


    Local $wbemFlagReturnImmediately = 0x10
    Local $wbemFlagForwardOnly = 0x20
    Local $colItems = ""
    Local $sReturn = ""
    Local $iExt = 0
    If 1 > Int($iLimit) Then $iLimit = 1
    Local $aReturn[1000][Int($iLimit) + 1]
    $aReturn[0][0] = 0
    $aReturn[0][1] = 0

    If $sComputer & $sUser & $sPassword = "." Then
        ToolTip("...ObjGet", @DesktopWidth - 30, @DesktopHeight - 130, "ScriptOMatic - Win32_LoggedOnUser", 1, 4)
        Local $oWMIService = ObjGet("winmgmts:\\" & $sComputer & "\root\CIMV2")
    Else
        ToolTip("...ObjCreate", @DesktopWidth - 30, @DesktopHeight - 130, "ScriptOMatic - Win32_LoggedOnUser", 1, 4)
        Local $wmiLocator = ObjCreate("WbemScripting.SWbemLocator")
        ToolTip("...ConnectServer", @DesktopWidth - 30, @DesktopHeight - 130, "ScriptOMatic - Win32_LoggedOnUser", 1, 4)
        Local $oWMIService = $wmiLocator.ConnectServer($sComputer, "\root\CIMV2", $sUser, $sPassword)
    EndIf

    ToolTip("...ExecQuery", @DesktopWidth - 30, @DesktopHeight - 130, "ScriptOMatic - Win32_LoggedOnUser", 1, 4)
    Local $colItems = $oWMIService.ExecQuery("SELECT * FROM Win32_LoggedOnUser", _
            "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)

    ToolTip("...ExecQuery executed." & @CR & "...waiting for data.", @DesktopWidth - 30, @DesktopHeight - 130, "ScriptOMatic - Win32_LoggedOnUser", 1, 4)
    If IsObj($colItems) Then

        ; Class Properties: Names:
        ;

        $aReturn[1][0] = "Antecedent"
        $aReturn[2][0] = "Dependent"
        $aReturn[0][0] = 2
        For $objItem In $colItems
            $aReturn[0][1] = $aReturn[0][1] + 1
            If Not Mod($aReturn[0][1], 100) Then ToolTip("...adding " & $aReturn[0][1] & " of " & $iLimit & " ??", @DesktopWidth - 30, @DesktopHeight - 130, "ScriptOMatic - Win32_LoggedOnUser", 1, 4)
            If $aReturn[0][1] > $iLimit Then
                $iExt = 2
                ExitLoop
            EndIf

            ; Class Properties: Values:
            ;

            $aReturn[1][$aReturn[0][1]] = $objItem.Antecedent
            $aReturn[2][$aReturn[0][1]] = $objItem.Dependent
        Next
        If $aReturn[0][1] = 0 Then $iExt = 1
        ReDim $aReturn[$aReturn[0][0] + 1][$aReturn[0][1] + 1]
        Return SetError(0, $iExt, $aReturn)
    Else
        ReDim $aReturn[1][2]
        Return SetError(1, 99, $aReturn)
    EndIf
EndFunc   ;==>_WMI_Win32_LoggedOnUser




Func _nice_COMerrorHandler($i = 0)
    If $i == 1 Then
        Dim $_nice_COMerrorArray[301][9]
        $_nice_COMerrorArray[0][0] = 0
        $_nice_COMerrorObj = ObjEvent("AutoIt.Error", "_nice_COMerrorHandler")
        Return
    EndIf
    If $i == 2 Then
        If Not @Compiled Then
            Local $s = FileRead(@ScriptFullPath)
            Local $a = StringSplit($s, @CRLF, 1)
            For $s = 1 To $_nice_COMerrorArray[0][0]
                If Int($_nice_COMerrorArray[$s][7]) > $a[0] Then ContinueLoop
                $_nice_COMerrorArray[$s][8] = StringStripWS($a[Int($_nice_COMerrorArray[$s][7])], 3)
            Next
        EndIf
        ReDim $_nice_COMerrorArray[$_nice_COMerrorArray[0][0] + 1][9]
        _ArrayDisplay($_nice_COMerrorArray, "ScriptOMatic - COM Errors intercepted ( the script will continue after this screen )")
        Return
    EndIf
    If $_nice_COMerrorArray[0][0] = 300 Then
        $_nice_COMerrorArray[0][8] = "ScriptLine: only first 300 errors shown !!!"
        Return
    EndIf
    $i = $_nice_COMerrorArray[0][0] + 1
    $_nice_COMerrorArray[0][0] = $i
    $_nice_COMerrorArray[$i][1] = "0x" & Hex($_nice_COMerrorObj, 8)
    $_nice_COMerrorArray[$i][2] = $_nice_COMerrorObj.windescription
    $_nice_COMerrorArray[$i][3] = $_nice_COMerrorObj.source
    $_nice_COMerrorArray[$i][4] = $_nice_COMerrorObj.helpfile
    $_nice_COMerrorArray[$i][5] = $_nice_COMerrorObj.helpcontext
    $_nice_COMerrorArray[$i][6] = $_nice_COMerrorObj.lastdllerror
    $_nice_COMerrorArray[$i][7] = $_nice_COMerrorObj.scriptline
    If $i == 1 Then
        $_nice_COMerrorArray[0][1] = "ErrorNumber:"
        $_nice_COMerrorArray[0][2] = "WinDescription:"
        $_nice_COMerrorArray[0][3] = "Source:"
        $_nice_COMerrorArray[0][4] = "HelpFile:"
        $_nice_COMerrorArray[0][5] = "HelpContext:"
        $_nice_COMerrorArray[0][6] = "LastDLLerror:"
        $_nice_COMerrorArray[0][7] = "ScriptLineNumber:"
        $_nice_COMerrorArray[0][8] = "ScriptLine:"
    EndIf
EndFunc   ;==>_nice_COMerrorHandler


#comments-start

List of all the Properties And Methods For \root\CIMV2 : Win32_LoggedOnUser


Win32_LoggedOnUser Class Qualifiers
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

1. Association = True
2. Description = The Win32_LoggedOnUser association represents the relationship between a session And the user account using that session. Although the association will usually be one To one - users are possible that involve more than one session. At the termination of the session the association instance is deleted.
3. dynamic = True
4. Locale = 1033
5. provider = CIMWin32
6. UUID = {8BB5B3EC - E1F7 - 4b39 - 942A - 605D5F55789A}


Win32_LoggedOnUser Class Properties And Property Qualifiers
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

1. Antecedent
1.1. CIMTYPE = ref : Win32_Account
1.2. Description = The Antecedent reference is the Account used In the initiation of this session. The account could be either a user account Or a system account.
1.3. key = True
1.4. read = True

2. Dependent
2.1. CIMTYPE = ref : Win32_LogonSession
2.2. Description = The Dependent reference is the session that the account is currently using.
2.3. key = True
2.4. read = True


Win32_LoggedOnUser Class Methods And Method Qualifiers
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

#Comments-End

 


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
timmy2

Under what account is your script ran when a user is logged off, I'm just a little confused you see.

If I'm correct it's either a normal process which runs under a user account or a service process that runs under the system account.

If It's ran under a user account and that user is logged off, then the task will probably not run at all.

Thank you for replying, JohnOne. When I create the task in Task Scheduler (W7) the current user is displayed in the field beneath "When running the task, use the following user account:".  In all cases the PC has only one user so that's fine. That user's credentials will be used by Task Scheduler to run the task.

Share this post


Link to post
Share on other sites
timmy2

Thank you, UEZ, but I'm not trying to pull a list of logged in users -- If I understand the point of your reply.

On a W7 PC with a single user, I've already verified that when Task Scheduler runs a script while the user is logged off, "@UserName" returns the username of that PC's only user. I had Task Scheduler run a simple script that fetched @UserName and wrote it to a file on the Desktop. Knowing the logged in Username won't tell me if my script ran while the user was logged off -- it's the same either way, at least via the @UserName macro.

Share this post


Link to post
Share on other sites
iamtheky

Have the script check the event log, starting from the most recent event working backwards, for  4624 or 4634, and that username.  If the most recent match is a 4624 the user is logged on, 4634 the user is logged off.   If they have network access or scheduled processes you may only want the type 2 logons.

 

Thank you, UEZ, but I'm not trying to pull a list of logged in users

but that also solves the problem, in that you just make sure the name is not on that list.

Edited by boththose

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Share this post


Link to post
Share on other sites
rudi
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce

... is another option to drop something to trigger a message showing up, when that user is doing his/her next logon.

 

Regards, Rudi.


Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Share this post


Link to post
Share on other sites
timmy2

All replies were appreciated but I was hoping there's an API call that can tell you if nobody is currently logged in. These are all single user PCs. So the user is either logged in or not. If the machine is in Sleep mode or Locked the user is still logged in and that's fine for my purposes. I was just looking for some indicator or flag to indicate the one exception: user is logged out, or to put it another way: no user is currently logged in. 

I have zero understanding of the Session 0 thing but I have a vague impression that when the user is logged off the system is in a different world, where sounds cannot be played, message boxes cannot be popped up, and no AutoIt keyboard or mouse activities will work. So I figured that "world" would have some kind of indicator.

Share this post


Link to post
Share on other sites
PACaleala

SYSTEM has an environment variable called USERNAME as in:

>echo %username%

W7

 

Share this post


Link to post
Share on other sites
timmy2

I was running on fumes when I wrote my reply last night. I failed to mention that looking for the username is pointless because Task Scheduler uses the username and password to run my program regardless of being logged in or not. So checking for @username will yield the same result regardless of whether the user is really logged in or it's just Task Scheduler.

Share this post


Link to post
Share on other sites
MuffinMan

So is there a process you can check for that would only exist while the user is logged on, or is there a process that would only exist while the user was away, like a logon.scr?  I'm not sure if the winlogon process only runs while waiting to logon or if it runs all the time.

Edited by MuffinMan

Share this post


Link to post
Share on other sites
iamtheky

count the number of processes started by that username, if it is more than the 1 process you are executing, then the user is logged in.

Edited by boththose

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

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

  • Similar Content

    • snoopy.pa30
      By snoopy.pa30
      I have a Windows 7 machine that is running a series of AutoIT 3 scripts from a master script. 
      When run manually, the entire set of scripts runs fine.  The scripts downloads data and do conversions and email results.
      When run from task scheduler, the  machine awakes and starts running the master script.  The first script runs fine, but the second part fails.  The first script is a simple call to an exe file that just runs.  The second script calls another exe file, but requires a few mouse clicks to run.  The further on scripts all run fine.
      When letting the script run from task scheduler (after being put to sleep) , if I move the mouse (or press a key), the login screen comes up (Strange, as No Password is set, and when machine boots, it comes straight into desktop).  If I click on the icon (no password) the scripts run fine.
      I am sure there is a setting somewhere that I have to set differently in task scheduler, or there is something in a W7 setting I need to change.
      My Task Scheduler quick tests are in the lines of: 
      Run only when user is logged on / Run whether user is logged on or not
      Run with Highest Privileges / or Not
      Configure for: (W7 / Vista / XP)
      Getting lost in the combinations, so will have to do a methodical series of tests, but hoping someone here might have some experience or suggestions.
      So, is it a Task Scheduler Setting (what combo) or a Windows 7 setting (what and where)?
      Any help or suggestion is appreciated.
      Thanks in Advance.
    • GreenCan
      By GreenCan
      This script will get all Scheduled tasks as defined on a system
      There are basically 3 functions in this small udf:
      _TaskGetFolders() will return an array of all folders as from a given Scheduler Library folder, recursively. $aFolders will have to be declared before the function is called, I am not sure if there is a better method to avoid having to declare the array outside of _TaskGetFolders()... _TaskListAllDetailed() will return a detailed array of all tasks in a given task folder, recursively. This function is using _TaskGetFolders() for the recurse option. _TaskListToText() will create a formatted output of scheduled tasks as returned to the above array. The script is complementary to taskplanerCOM.au3 by Allow2010.
      The example shows
      all folders in the Scheduler Library All scheduled tasks in root (with formatted output) All scheduled tasks on the system Scheduled tasks Windows Defender if available _TaskListAllDetailed.au3
       
    • shmuelw1
      By shmuelw1
      I tried to start Skype via Task Scheduler, but when it started, it only ran in the background. Then I made an AutoIt script to open the Start menu, type the path to Skype and press Enter. That also didn't work. The Task Schedular claimed the process started, but I didn't see anything happening.

      After doing some research, I found out that the problem was that I selected the checkbox in Task Scheduler to run the task even when I'm not logged in. When you do that, Task Scheduler runs the task in the background, so you can't see the started program.

      I didn't see anyone mention this on the forum, so I thought I'd mention this here.
×