How to determine if XP Pro is logged off or locked by VB.Net scheduled task

Posted on 2007-10-05
Last Modified: 2008-02-07
Need to know in VB.Net (pref .Net 1.1) how determine if a WinXp Pro computer is locked or logged off.

I want to write an app that's run in the task scheduler nightly that determines if the computer is "logged off" and if so to reboot it.

There should be NO reboot (and it should email me) if the computer is locked at that time, which means that a user may have left applications/files open.

Thanks, Jeff

    LVL 41

    Accepted Solution

    An easy way to know if there is anybody logged in or not is to check whether there is an Explorer.exe process running.   The Processes class has a useful GetProcessByName method

    Author Comment

    Thanks, that was very helpful. Through testing your suggestion, I did find that the explorer process was not running when logged off, but was there when locked, so that's perfectly definitive for what I neded. :-)

    By the way, I tried to obtain a list of processes remotely from another box (on the same LAN) using the overloaded method of Process.GetProcessesByName("EXPLORER", "IP_Address") , but couldn't, and exception was thrown, the message something like Proccesses cannot be obtained.

    I thought this might be a Win XP Pro firewall issue, so I turned it off, but still no luck, do you know what's preventing me from being able to obtain that?
    LVL 41

    Expert Comment

    This class uses Remote Procedure Calls (RPC) for performing it's functions across the network.  So, there's the usual things that have to be right...

    Services (RPC)
    Firewall (which you've already looked at)
    User Account/Permission (the account used must be in the Administrators group on both PCs)

    Author Comment

    Hi graye:
    You have definitely earned the points on your original answer. I can award them now, however, if you can help me access this remotely, I will award an add'l 250. Do you want to go forward?

    If so. the follow-up questions to your last answer:
    "there's the ususal things that have to be right"
    1. "Services (RPC)". I take this to mean that "Remote Procedure Call (RPC)" service must be running. It is "Automatic", however, RPC locator service is "Manual" and is not running. Is that important?

    2. Firewall. Yes I have turned it off and tried with no luck.

    3. User account I hadn't thought of. There is no domain, it's peer to peer (server 2003 O/S accessing a win Xp Pro on same LAN). I added in as a user into the XP Pro box the same user name w/ same password as what I'm logged into on the server, both administrators on their own machine, but still no luck

    The server is trying to get the services form the XP Pro box.

    FYI I just tried to shutdown the WinXp Pro box from the server using shutdown.exe (part of windows) and got the error:
    "Access denied.(5)"

    Any ideas?
    LVL 41

    Expert Comment

    Hummmm....  that's a bit strange.  

    1) RPC... that looks normal
    2) Did you make sure you turned off the firewall on both systems?
    3) Typically, in a workgroup environment, all you need is to be using a user name and password that's common to both systems.  That account must also be in the Administrators group on both systems.  Note:  The password can NOT be blank.  

    Here is an example of how to get the name of the user who is logged onto a remote PC.   It uses Remote Registry Services (yet another thing to check for in the Services control panel applet)

    Imports Microsoft.Win32

    ' Class to get the name of the remotely logged in user

    Public Class GetUser

    #Region "API Region"
        'BOOL LookupAccountSid(
        '  LPCTSTR lpSystemName,
        '  PSID lpSid,
        '  LPTSTR lpName,
        '  LPDWORD cchName,
        '  LPTSTR lpReferencedDomainName,
        '  LPDWORD cchReferencedDomainName,
        '  PSID_NAME_USE peUse
        Private Declare Auto Function LookupAccountSid Lib "advapi32.dll" ( _
            ByVal lpSystemName As String, _
            ByVal lpSid As IntPtr, _
            ByVal lpName As String, _
            ByRef cchName As Integer, _
            ByVal lpReferenceDomainName As String, _
            ByRef cchReferencedDomainName As Integer, _
            ByRef peUse As Integer _
        ) As Boolean

        'BOOL ConvertStringSidToSid(
        '  LPCTSTR StringSid,
        '  PSID* Sid
        Private Declare Auto Function ConvertStringSidToSid Lib "advapi32.dll" ( _
            ByVal StringSid As String, _
            ByRef Sid As IntPtr _
        ) As Boolean

        Private Const NAME_SIZE As Integer = 64
    #End Region

        Public Function GetRemoteUser(ByVal RemotePC As String) As String
            Dim reg_hku, key, subkey As RegistryKey
            Dim user, keyname, CurKey, UserName, DomainName As String
            Dim name_len, domain_len, peUse As Integer
            Dim got_it As Boolean
            Dim Sid As IntPtr

            CurKey = ""
            user = "Error"
                reg_hku = RegistryKey.OpenRemoteBaseKey(RegistryHive.Users, RemotePC)
                If Not IsNothing(reg_hku) Then
                    ' Find the User key that has "Volatile Environment"... that's
                    ' either the current user or the last user logged in.
                    got_it = False
                    For Each keyname In reg_hku.GetSubKeyNames()
                        key = reg_hku.OpenSubKey(keyname, False)
                        If Not IsNothing(key) Then
                            If Array.IndexOf(key.GetSubKeyNames(), "Volatile Environment") >= 0 Then
                                CurKey = keyname
                                ' for WinXP's alternate login, we must check to
                                ' see if the CLIENTNAME is "Console"
                                subkey = key.OpenSubKey("Volatile Environment")
                                If Not IsNothing(subkey) Then
                                    If subkey.GetValue("CLIENTNAME", "").ToString = "Console" Then
                                        got_it = True
                                    End If
                                End If
                            End If
                            If got_it Then
                                Exit For
                            End If
                        End If
                End If

                ' Nope, didn't find anything
                If CurKey = "" Then
                    Return "Nobody"
                End If

                ' In rare cases, the user's registry hive is still loaded.  So
                ' to test if there is anybody currently logged on, we see if
                ' the remote PC has an explorer.exe process running
                If Process.GetProcessesByName("explorer", RemotePC).Length = 0 Then
                    Return "Nobody"
                End If

                ' Now let's get the logon name from the string version of the
                ' Sid (which is the registry key name)
                If ConvertStringSidToSid(CurKey, Sid) = False Then
                    Return "Error"
                End If

                name_len = NAME_SIZE
                domain_len = NAME_SIZE
                UserName = Space(name_len)
                DomainName = Space(domain_len)

                ' look up the Account associated with that SID
                If LookupAccountSid(RemotePC, Sid, UserName, name_len, DomainName, domain_len, peUse) = False Then
                    Return "Error"
                End If
                If domain_len > 0 Then
                    user = Left(DomainName, domain_len) & "\" & Left(UserName, name_len)
                    user = RemotePC & "\" & Left(UserName, name_len)
                End If
            Catch ex As Exception
                Return "Error"
            End Try

            Return user
        End Function
    End Class


    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Maximize Your Threat Intelligence Reporting

    Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

    This article explains how to create and use a custom WaterMark textbox class.  The custom WaterMark textbox class allows you to set the WaterMark Background Color and WaterMark text at design time.   IMAGE OF WATERMARKS STEPS Create VB …
    It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
    Sending a Secure fax is easy with eFax Corporate ( First, Just open a new email message.  In the To field, type your recipient's fax number You can even send a secure international fax — just include t…
    This video discusses moving either the default database or any database to a new volume.

    760 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    13 Experts available now in Live!

    Get 1:1 Help Now