Link to home
Start Free TrialLog in
Avatar of JEFFCECCHINI
JEFFCECCHINI

asked on

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

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

ASKER CERTIFIED SOLUTION
Avatar of graye
graye
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of JEFFCECCHINI
JEFFCECCHINI

ASKER

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?
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)
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)"
"Failed: 192.168.222.11"

Any ideas?
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"
        Try
            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
                                subkey.Close()
                            End If
                        End If
                        key.Close()
                        If got_it Then
                            Exit For
                        End If
                    End If
                Next
                reg_hku.Close()
            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)
            Else
                user = RemotePC & "\" & Left(UserName, name_len)
            End If
        Catch ex As Exception
            Return "Error"
        End Try

        Return user
    End Function
End Class