Jump to content

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


Recommended Posts

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
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

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

Link to comment
Share on other sites

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!

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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
Link to comment
Share on other sites

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

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

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