I am trying to programmatically find who last logged onto a given computer and when with C#. Given the name of a computer as a string, I have learned about Getting last Logon Time on Computers in Active Directory. However, there doesn't seem to be a property for which user was the one that actually logged in. Do I have to take a different approach for this? Anything I found online that was remotely related to this was in VBScript, but this must be done in C#.
-
1I think you have to do it via looking through the Security Event Log on the machine in question or on the domain controller. I don't think ActiveDirectory itself stores that information. – Scott Chamberlain Nov 07 '13 at 17:13
-
.. or the Security Event Log on the domain controller – Andrew Cooper Nov 07 '13 at 17:13
-
Have you made any progress on this? What possible solutions have you tried? – Derek W Nov 08 '13 at 13:15
-
Where can I learn more about this Security Event Log on the domain controller and do you know how I would read it with C#? – Baga Jr. Feb 28 '14 at 16:37
2 Answers
Simply query the necessary information from the System Registry. The following method will set the Registry View based on whether the machine is 64-bit or 32-bit - although if you're doing this remotely - then the approach to obtain this information may need to be altered, but the general approach should be the same.
The Base Key is selected using the name of the machine that you pass an argument along with the Registry View and of course the Registy Hive as Local Machine. Then you open up the Base Key and finally the necessary Sub Key where the information you desire resides.
The location where that information is contained is:
SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI
And from there grab the value from LastLoggedOnUser
.
Here is the code in C#:
private static string GetLastUserLoggedOn(string machineName)
{
string location = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI";
var registryView = Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32;
using (var hive = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, machineName, registryView))
{
using (var key = hive.OpenSubKey(location))
{
var item = key.GetValue("LastLoggedOnUser");
string itemValue = item == null ? "No Logon Found" : item.ToString();
return itemValue;
}
}
}

- 9,708
- 5
- 58
- 67
-
I know the basics on working with registry keys in C#, but I haven't found any guide on how to do it remotely. Everything I find online is basically the same as what you put. However, I thought that that was the point of OpenRemoteBaseKey; isn't it already doing it remotely? I got thrown into this to learn as I work and I only go to this class every other school day and I only sometimes get to work on this so sorry about very delayed responses and the lack of experience. – Baga Jr. Dec 12 '13 at 16:21
Here is some code I found:
using System;
// has DateTime class
using System.Collections.Generic;
// has the Dictionary class
using System.DirectoryServices;
// has all the LDAP classes such as DirectoryEntry
using ActiveDs;
// has the IADsLargeInteger class
// Get the root entry
DirectoryEntry rootDSE = new DirectoryEntry("LDAP://RootDSE");
string configurationNamingContext =
(string)rootDSE.Properties["configurationNamingContext"].Value;
string defaultNamingContext =
(string)rootDSE.Properties["defaultNamingContext"].Value;
// Get all the domain controllers
// Get all the domain controllers
DirectoryEntry deConfig =
new DirectoryEntry("LDAP://" + configurationNamingContext);
DirectorySearcher dsConfig = new DirectorySearcher(deConfig);
dsConfig.Filter = "(objectClass=nTDSDSA)";
foreach (SearchResult srDomains in dsConfig.FindAll())
{
DirectoryEntry deDomain = srDomains.GetDirectoryEntry();
if (deDomain != null)
{
string dnsHostName =
deDomain.Parent.Properties["DNSHostName"].Value.ToString();
// Get all the users for that domain
}
}
// Get all the users for that domain
DirectoryEntry deUsers =
new DirectoryEntry("LDAP://" + dnsHostName + "/" + defaultNamingContext);
DirectorySearcher dsUsers = new DirectorySearcher(deUsers);
dsUsers.Filter = "(&(objectCategory=person)(objectClass=user))";
foreach (SearchResult srUsers in dsUsers.FindAll())
{
DirectoryEntry deUser = srUsers.GetDirectoryEntry();
if (deUser != null)
{
// Get the distinguishedName and lastLogon for each user
// Save the most recent logon for each user in a Dictionary object
}
}
//Create Dictionary
Dictionary<string, Int64> lastLogons = new Dictionary<string, Int64>();
// Get the distinguishedName and lastLogon for each user
string distinguishedName =
deUser.Properties["distinguishedName"].Value.ToString();
Int64 lastLogonThisServer = new Int64();
if (deUser.Properties["lastLogon"].Value != null)
{
IADsLargeInteger lgInt =
(IADsLargeInteger)deUser.Properties["lastLogon"].Value;
lastLogonThisServer = ((long)lgInt.HighPart << 32) + lgInt.LowPart;
}
// Save the most recent logon for each user in a Dictionary object
if (lastLogons.ContainsKey(distinguishedName))
{
if (lastLogons[distinguishedName] < lastLogonThisServer)
{
lastLogons[distinguishedName] = lastLogonThisServer;
}
}
else
{
lastLogons.Add(distinguishedName, lastLogonThisServer);
}
//Get the time
// Convert the long integer to a DateTime value
string readableLastLogon =
DateTime.FromFileTime(lastLogonThisServer).ToString();
Here is the website where all of this code came from. The developer explained the code in detail. http://www.codeproject.com/Articles/19181/Find-LastLogon-Across-All-Windows-Domain-Controlle

- 1,818
- 3
- 35
- 56
-
That's last logon *time*. I said I already accomplished that and I need to find the user that logged in at that time. I don't think this approach would work for last user logged on because there doesn't seem to be a property in DirectoryEntry for that. – Baga Jr. Dec 18 '13 at 16:59