Tonmoy chowdhury
Tonmoy chowdhury

Reputation: 51

Find idle time from remote pc using c#

I need to find out the idle time of remote pc from server pc using c# application. I have a list of IP addresses and host names connected in Local Area Network. I want to find out idle time more then 30 min for each computer connected in LAN. I done it for local pc, but it not works for remote pc. here is my code for local pc.

[DllImport("user32.dll")]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

 private int GetIdleTime()
{
    LASTINPUTINFO lastone = new LASTINPUTINFO();
    lastone.cbSize = (uint)Marshal.SizeOf(lastone);
    lastone.dwTime = 0;

    int idleTime = 0;

    int tickCount = Environment.TickCount;
    if (GetLastInputInfo(ref lastone))
    {
        idleTime = tickCount - (int)lastone.dwTime;
        return idleTime;
    }
    else
        return 0;
}

Upvotes: 0

Views: 2087

Answers (3)

Rahvin47
Rahvin47

Reputation: 91

I use this remote WMI query:

object idleResult = Functions.remoteWMIQuery(machinename, "", "", "Select CreationDate From Win32_Process WHERE Name = \"logonUI.exe\"", "CreationDate", ref wmiOK);

Logonui.exe is the lockscreen. In business environments most systems lock when a user is idle.

You can translate the result like this in DateTime format

DateTime idleTime = Functions.ParseCIM_DATETIME((string)idleResult);

Where ParseCIM_DATETIME is this fucntion:

public static DateTime ParseCIM_DATETIME(string date)
    {
        //datetime object to store the return value
        DateTime parsed = DateTime.MinValue;

        //check date integrity
        if (date != null && date.IndexOf('.') != -1)
        {
            //obtain the date with miliseconds
            string newDate = date.Substring(0, date.IndexOf('.') + 4);

            //check the lenght
            if (newDate.Length == 18)
            {
                //extract each date component
                int y = Convert.ToInt32(newDate.Substring(0, 4));
                int m = Convert.ToInt32(newDate.Substring(4, 2));
                int d = Convert.ToInt32(newDate.Substring(6, 2));
                int h = Convert.ToInt32(newDate.Substring(8, 2));
                int mm = Convert.ToInt32(newDate.Substring(10, 2));
                int s = Convert.ToInt32(newDate.Substring(12, 2));
                int ms = Convert.ToInt32(newDate.Substring(15, 3));

                //compose the new datetime object
                parsed = new DateTime(y, m, d, h, mm, s, ms);
            }
        }

        //return datetime
        return parsed;
    }

The remote WMI Query function is as follows:

public static object remoteWMIQuery(string machine, string username, string password, string WMIQuery, string property, ref bool jobOK)
    {
        jobOK = true;
        if (username == "")
        {
            username = null;
            password = null;
        }
        // Configure the connection settings.
        ConnectionOptions options = new ConnectionOptions();
        options.Username = username; //could be in domain\user format
        options.Password = password;
        ManagementPath path = new ManagementPath(String.Format("\\\\{0}\\root\\cimv2", machine));
        ManagementScope scope = new ManagementScope(path, options);

        // Try and connect to the remote (or local) machine.
        try
        {
            scope.Connect();
        }
        catch (ManagementException ex)
        {
            // Failed to authenticate properly.
            jobOK = false;
            return "Failed to authenticate: " + ex.Message;
            //p_extendederror = (int)ex.ErrorCode;
            //return Status.AuthenticateFailure;
        }
        catch (System.Runtime.InteropServices.COMException)
        {
            // Unable to connect to the RPC service on the remote machine.
            jobOK = false;
            return "Unable to connect to RPC service";
            //p_extendederror = ex.ErrorCode;
            //return Status.RPCServicesUnavailable;
        }
        catch (System.UnauthorizedAccessException)
        {
            // User not authorized.
            jobOK = false;
            return "Error: Unauthorized access";
            //p_extendederror = 0;
            //return Status.UnauthorizedAccess;
        }

        try
        {
            ObjectQuery oq = new ObjectQuery(WMIQuery);
            ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, oq);

            foreach (ManagementObject queryObj in searcher.Get())
            {
                if (property != null)
                {
                    return queryObj[property];
                }
                else return queryObj;
            }
        }
        catch (Exception e)
        {
            jobOK = false;
            return "Error: " + e.Message;
        }
        return "";
    }

Upvotes: 1

Sandri_Nenes
Sandri_Nenes

Reputation: 173

If you have the screensaver enabled I would suggest you check the CreateDate on the screensaver process and do a difference from the remote the createdate time and you get the idle time + the screensaver timeout

you might want to use WMI for this kind of thing

its a hack but it works

Upvotes: 0

Daro
Daro

Reputation: 2020

Acording to MSDN, this is not possible entirely for the local machine let alone a remote one.

This function is useful for input idle detection. However, GetLastInputInfo does not provide system-wide user input information across all running sessions. Rather, GetLastInputInfo provides session-specific user input information for only the session that invoked the function.

You could however try one of the following:

  • Have a process on each PC which you can query.
  • Have a process on each PC reporting to your central process.
  • Monitor remote PC processes to determine if the screen saver is active.

If you do not have terminal services deactivated, and the clients are xp or higher, you can also use

ITerminalServicesSession.LastInputTime

For this you either use the Cassia libraries or p/invoke

WTSQuerySessionInformation

Upvotes: 1

Related Questions