Check for logged on user on Windows machine

Motivated by a posting in a user group I tried to find the answer to the question: How can a Windows Service find out, if a user has already logged onto the machine it is running on?

I googled for a while and it seems, there is no simple function like "IsUserLoggedOn" in the Win32 API or in the .NET Fx base class library. But I stumbled across a hint which pointed into the direction of WMI as a solution.

So here is my VB.NET version of the function IsUserLoggedOn(). It gets a list of all processes on a machine from WMI and asks each one for the name of the user it is running under. So if a Windows Service is checking for a certain user, e.g. John Doe, if he has already logged on, it just needs to call the function periodically. (If instead it wants to check if any user has logged on, it needs to see, if processes exist running under a non-system account.)

Imports System.Management

Module Module1
    Sub Main()
        Console.WriteLine(IsUserLoggedOn("John Doe"))
    End Sub


    Private Function IsUserLoggedOn(ByVal userName As String) As Boolean
        Dim mc As New ManagementClass("Win32_Process")
        Dim moc As ManagementObjectCollection = mc.GetInstances
        Dim mo As ManagementObject
        For Each mo In moc
            Dim p As New ROOT.CIMV2.Process(mo)

            Dim processDomain, processUser As String
            p.GetOwner(processDomain, processUser)
            If processUser = userName Then
                Return True
            End If
        Next
    End Function
End Module

For this code to work you need to reference the WMI library assembly System.Management in your project. Then download the WMI Server Explorer Add-In for VS.NET 2003 (see resources below) and create a managed class (ROOT.CIMV2.Process) for the Processes node in the Management Classes branch of the server explorer. Include the above function IsUserLoggedOn() and you´re set.

Resources:

-A introductory article on WMI:
http://msdn.microsoft.com/msdnmag/issues/02/05/WMIMan/default.aspx

-Download link for WMI Server Explorer Add-In for VS.NET 2003
http://www.microsoft.com/downloads/details.aspx?familyid=62d91a63-1253-4ea6-8599-68fb3ef77de1&displaylang=en

 

10 Comments

  • Another way to do this would be to P/Invoke NetUserEnum asking for USER_INFO_2 structs to be returned, and check for the usri2_last_logon for example.



    I haven't checked, but maybe WMI has a method for getting this information too.

  • ... if Windows-Services are startet under a user specific login (=not localsystem).



    i think, enumeration lastlogin is the better

    and surer way.



    (michael, the original newsgroup-poster)

  • i don´t agree with michael: the last login time only shows - as its name says - the last login. it does not provide a means to determine, if the user is still logged in, when a Windows service checks the timestamp. So with last login you only can check, if a user has logged in after a certain point in time. not more.

  • hi ralph,



    thanks for your hints,

    may be i'll use a combination of the

    wmi- and lastlogin-solution

    and in the wmi-suggestion the userspecific-iexplorer.exe-process.



    thanks,

    and happy new year.

    michael

  • This works for me:



    Set objWMIService = GetObject("winmgmts:" _

    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")



    Set objSystemSet = objWMIService.InstancesOf ("Win32_ComputerSystem")

    For Each System in objSystemSet

    sUserName = System.UserName

    Wscript.echo sUserName

    Next



    where 'strComputer' is the system you want to check; use '.' for the local system

  • Here's the C# equivalent with the domain handling added.
    private static bool IsUserLoggedOn(string domain, string user)
    {
    ManagementClass mc = new ManagementClass("Win32_Process");
    ManagementObjectCollection moc = mc.GetInstances();

    foreach (ManagementObject baseObject in moc)
    {
    Process process = new Process(baseObject);
    string processDomain, processUser;
    process.GetOwner(out processDomain, out processUser);
    if ((domain == null || processDomain == domain) && processUser == user)
    {
    return true;
    }
    }
    return false;
    }

  • regarding the C# equivalent by Arthur: thank you for this solution - this piece of code has been working beautifully for me up until today (server got rebooted after a Windows update).

    now, when I attempt to build it, I get the dreaded "The type or namespace name 'Process' could not be found (are you missing a using directive or an assembly reference?"

    what could I be missing today that was there before the reboot?

  • How can i know, if Windows was logged with any user or it's in "Welcome Window"

  • i just use:
    nbtstat -a machinename

  • I just check to see if explorer.exe is running. Explorer.exe is only running if a user is logged in.

Comments have been disabled for this content.