In a C# Windows Forms Application, I'm trying to get a list of the users currently logged into a workstation (both local and domain users). Every search about this has led me to threads mentioning "just use LsaEnumerateLogonSessions".
So...how do you actually use this? The MSDN page is very sparse and doesn't seem to offer any clues.
This article shows how to use LsaEnumerateLogonSessons:
http://www.codeproject.com/Articles/18179/Using-the-Local-Security-Authority-to-Enumerate-Us
You should use Cassia, an open source wrapper.
ITerminalServicesManager manager = new TerminalServicesManager();
using (ITerminalServer server = manager.GetRemoteServer("your-server-name"))
{
server.Open();
foreach (ITerminalServicesSession session in server.GetSessions())
{
Console.WriteLine("Session ID: " + session.SessionId);
Console.WriteLine("User: " + session.UserAccount);
Console.WriteLine("State: " + session.ConnectionState);
Console.WriteLine("Logon Time: " + session.LoginTime);
}
}
I'm not sure how this will handle domain users; try it in LINQPad.
To answer your question, you need to declare it as a P/Invoke method that takes an out in and an out long[].
Related
Straight to the point, I have a request for a new project on which I have to find the primary and secondary owners for a specific list of Active Directory groups. When I get the array of secondary owners for each group, each of the owners are identified by their "distinguishedName" which led me to use a snippet like this to get the owner's info:
using (DirectoryEntry entry = new DirectoryEntry("LDAP://" + distinguishedName))
{
using (DirectorySearcher dSearch = new DirectorySearcher(entry))
{
SearchResult found = dSearch.FindOne();
if (found != null)
{
using (DirectoryEntry userEntry = found.GetDirectoryEntry())
{
Console.WriteLine("Username: " + userEntry.Properties["namefield"].Value + " : " + userEntry.Properties["emailfield"].Value);
}
}
else
{
Console.WriteLine("User not found with distinguishedName: " + distinguishedName);
}
}
}
GC.Collect();
I am a little concerned by the performance of this task since I have to get this information at the page loading sequence to check if the logged user is an owner or not. I have other AD browsing task to do and I've been doing some research on best practices with C# and AD and haven't found anything helpful yet so I though that you guys could provide some input on this.
Thanks for all your help.
f you have distinguished name of an object, you can bind to the object directly. Searching with DirectorySearcher is an excessive operation. Just create DirectoryEntry object and call its RefreshCache method. The fastest performance in ad is provided by classes located under System.DirectoryServices.Protocols namespace. Also one more optimization can be done: at the start of your program create a DirectoryEntry object and bind, e. g. To rootdse. This will establish ldap connection under the hood. All other queries will use this ldap connection. Keep the object alive until the program finishes
Credit to: oldovets
I have a C# WPF applicaiton that I am trying to perform a light check with the Active Directory Server and am running into serious performance issues of 20-30 seconds for the funciton to run. Using the identical code, I can place it in a Winforms application and it takes about 1 second or less. Since it is a big AD, I am guessing it is pulling all properties for the end user, but I really only want the first and last name of the person (for other purposes), and to ensure the user is in Active Directory.
Here is the code:
public string DomainUserNameGet(string ActiveDirectoryServer, string WindowsUserID) {
/// queries AD to get logged on user's name
string results = "";
try {
// create your domain context
PrincipalContext oPrincipalContext = new PrincipalContext(
ContextType.Domain
, ActiveDirectoryServer
);
UserPrincipal oUserPrincipal = UserPrincipal.FindByIdentity(
oPrincipalContext
, IdentityType.SamAccountName
, ActiveDirectoryServer + #"\" + WindowsUserID
);
results =
oUserPrincipal.GivenName.ToString()
+ " "
+ oUserPrincipal.Surname.ToString();
} catch { }
return results;
}
The crazy thing is I can do the following via command line and get the response in about 1 second:
NET USER /DOMAIN LANID | find "LANID" /c
Any ideas on how I can improve performance?
RenniePet had it right; Turns out there was a DNS issue; I am unsure why this showed up in WPF vs. win forms though.
As I come across issues when testing my current application, I often have to tweak the database the app uses. After losing important changes several times, I wrote a program that will back up my database to a file and then check the file into SubVersion. I have found that that backup application is not good enough.
The database is a PostgreSQL database, and my backup application invokes pg_dump to create the backup file. pg_dump is executed in a console window. When the database was on my own machine, it worked well. But when I moved the database to our test server, pg_dump asked for a password. While it's not that big a deal, I'd like to be able to supply the password automatically, since it is available in the backup application.
I've tried to follow advice I've found here, but pg_dump still stops and asks for a password. Here's the code that I thought should have supplied the password:
Process backupProcess = new Process();
backupProcess.StartInfo.UseShellExecute = false;
backupProcess.StartInfo.RedirectStandardInput = true;
backupProcess.StartInfo.FileName = dumpPath + "pg_dump.exe";
backupProcess.StartInfo.Arguments = " --host " + host +
" --port " + port +
" --username " + userName +
" --format custom --blobs --verbose --file " +
"\"" + txtBackupFile.Text + "\" " + dbName;
backupProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
backupProcess.Start();
StreamWriter standardInput = backupProcess.StandardInput;
standardInput.WriteLine("mypassword");
backupProcess.WaitForExit();// Waits here for the process to exit.
Thank you for your help.
RobR
I have solved this by using
backupProcess.EnvironmentVariables["PGPASSWORD"] = "password";
This way, I avoid the password will be stored on the computer
Maybe it's cheating a little bit (in the sense that it doesn't really help you answer the question of how to feed input to pg_dump), but you could refer to this answer which suggests the use of a .pgpass file. It would certainly be possible to write to this file dynamically rather than try to interact with the program once it prompts.
Info on .pgpass here.
I need to change Network settings like described in this article. That works good so far. However I also need to know on what active network I make the changes.
(For a better understanding please open Control Panel\Network and Internet\ Network and Sharing Center. Unfortunately all picture hosting sites are blocked by my company so I can't post a screenshot.)
Any help on how I can query what connection is associated with what network with WMI (or other technology)?
UPDATE:
I need to query a remote machine.
You can use the NetworkListManager COM component, either with dynamic as shown below or using the Windows API Code Pack which contains all the COM wrappers.
dynamic networkListManager = Activator.CreateInstance(
Type.GetTypeFromCLSID(new Guid("{DCB00C01-570F-4A9B-8D69-199FDBA5723B}")));
var connections = networkListManager.GetNetworkConnections();
foreach (var connection in connections)
{
var network = connection.GetNetwork();
Console.WriteLine("Network Name: " + network.GetName());
Console.WriteLine("Network Category " +
network.GetCategory()+ " (0 public / 1 private / 2 Authenticated AD)" );
}
PowerShell:
$networkType = [Type]::GetTypeFromCLSID('DCB00C01-570F-4A9B-8D69-199FDBA5723B')
$networkListManager = [Activator]::CreateInstance($networkType)
$netWorks = $networkListManager.GetNetworkConnections()
foreach ($network in $netWorks)
{
$name = $network.GetName()
$category = $network.GetCategory()
write-host "Network Name: $name"
write-host "Network Category: $category"
}
I need to detect the logged on time of a user connected to the server by remote desktop or console in C#. I was trying to search a property in the WMI classes but I did not find any.
Thanks again in advance!
Check out cassia, the .NET Terminal Services Library.
ITerminalServicesManager manager = new TerminalServicesManager();
using (ITerminalServer server = manager.GetRemoteServer("your-server-name"))
{
server.Open();
foreach (ITerminalServicesSession session in server.GetSessions())
{
Console.WriteLine("Session ID: " + session.SessionId);
Console.WriteLine("User: " + session.UserAccount);
Console.WriteLine("State: " + session.ConnectionState);
Console.WriteLine("Logon Time: " + session.LoginTime);
}
}
You could also use P/Invoke to access the Windows Terminal Services API directly, but cassia wraps it for you.