I have a sonicwall on a network of around 100 machines.
I have tried and tried to find a way of creating 2 combobox's that will contain both the IP addresses linked to the sonicwall, as well as the currently logged in user of the machine as well.
What i am trying to create is a employee monitoring software (like Interguard/ActivTrak/etc), but am unable at present to even get near to finding this information?
I've been researching A LOT of stuff (~25 pages of google, with not a single link not clicked), and have met no conclusion as to get this information.
I'm not exactly a great programmer, but I would LOVE to be able to get this sort of information into two combobox's/arrays/other suitable object/control.
If anyone knows a way of even creating an array of IP addresses, along with corresponding Logins, that would be of great help to this project!
(PLEASE NOTE: I know there is a Networking exchange site, but I have already looked! Also, since i'm designing a piece of software for this, I thought i'd ask it here!)
Thanks for any advice/suggestions much appreciated!
What you looking for is similar to a packet sniffer application like wireshark or ethereal. But if you want to design it yourself, I think your best solution is a collection/list to store the data that is binded to a datagrid.
If you're in an Active Directory domain, you could use the code from my S/O question. Instead of using the CheckConnectionAsync() method to check for connectivity, you could just re-write it to get the IP address using System.Net.Dns.
To retrieve the user, you can use WMI. For this, you need to make a reference to the System.Management namespace.
public Task<string> GetUserName(string ComputerName)
{
return Task.Run(() =>
{
ConnectionOptions conn = ConnectionOptions()
{
EnablePrivileges = true,
Username = // string in format of #"DomainName\UserName",
Password = password,
Authentication = AuthenticationLevel.PacketPrivacy,
Impersonation = ImpersonationLevel.Impersonate
};
ManagementScope scope = new ManagementScope(#"\\" + ComputerName + #"\root\cimv2", conn);
try
{
scope.Connect();
ObjectQuery user = new ObjectQuery("Select UserName From Win32_ComputerSystem");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, user);
ManagementObjectCollection collection = searcher.Get();
foreach (ManagementObject m in collection)
{
string username = m["UserName"].ToString().Trim();
if(!String.IsNullOrEmpty(username))
{
return username;
}
}
return null; // no current logged in user
}
catch (Exception) // error handling...
});
}
Then, just iterate through your collection of computers and retrieve the username like so:
private async Task RetrieveUsers()
{
Parallel.ForEach(Computers, c =>
{
string user = await GetUserName(c.Name); // or c.IP. both work.
});
}
Related
I'm researching what I need to build an Active Directory search tool which ultimately will be used in a C# ASP.NET web app.
I know very little about AD (and don't particularly want to know any more than necessary) so I've asked our tech ops to set up a dummy instance on a server. This they've done giving it the domain dummy.local
I now need to work out my LDAP connection string. Here I'm completely stuck. I'm using a user account which is a member of Domain Admins. After loads of hunting round the web I've tried all sorts of things to work out the various components of the LDAP connection string. For example, if I run the following in cmd.exe for that domain admin user on the server...
dsquery user -samid "username" | dsget user -memberof -expand
...this gives me the following information:
"CN=Domain Admins,CN=Users,DC=dummy,DC=local"
"CN=Remote Desktop Users,CN=Builtin,DC=dummy,DC=local"
"CN=Users,CN=Builtin,DC=dummy,DC=local"
"CN=Administrators,CN=Builtin,DC=dummy,DC=local"
"CN=Domain Users,CN=Users,DC=dummy,DC=local"
"CN=Denied RODC Password Replication Group,CN=Users,DC=dummy,DC=local"
I've also run the following in a C# console app...
using (var context = new PrincipalContext(ContextType.Domain))
using (var comp = ComputerPrincipal.FindByIdentity(context, Environment.MachineName))
{
Console.WriteLine(String.Join(",", comp.DistinguishedName.Split(',').SkipWhile(s => !s.StartsWith("OU=")).ToArray()));
}
...and this gives me the following:
OU=Domain Controllers,DC=dummy,DC=local
I thought I therefore had all the properties I needed to build my LDAP connection string. I ended up with this:
LDAP://COMSECWEBDEV.dummy.local/ou=Domain Controllers,/cn=Domain Admins,/cn=Users,/dc=dummy,/dc=local
I've tried using this connection string, with the username and password of the domain admin which I know is correct, but everything I try always gives me the same error:
System.Runtime.InteropServices.COMException (0x80005000): Unknown error (0x80005000)
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
at System.DirectoryServices.DirectorySearcher.FindOne()
Since this error gives me no detail I have no idea what I'm doing wrong. I'm sure I'm just not getting the connection string right, but I've no idea how to work out the correct string.
For completeness, here is the console code which I'm testing with:
static void Main(string[] args)
{
var connString = ConfigurationSettings.AppSettings["lc"];
var username = ConfigurationSettings.AppSettings["lu"];
var password = ConfigurationSettings.AppSettings["lpw"];
using (DirectoryEntry de = new DirectoryEntry(connString, username, password))
{
DirectorySearcher search = new DirectorySearcher(de);
search.PageSize = 1001;// To Pull up more than 100 records.
DirectorySearcher directorySearcher = new DirectorySearcher(de);
directorySearcher.Filter = string.Format("(&(objectClass=user)(objectCategory=user) (sAMAccountName={0}))", username);
directorySearcher.PropertiesToLoad.Add("msRTCSIP-PrimaryUserAddress");
try
{
var result = directorySearcher.FindOne();
var found = false;
if (result != null)
{
if (result.Properties["msRTCSIP-PrimaryUserAddress"] != null)
{
found = true;
Console.WriteLine("Found: " + result.Properties["msRTCSIP-PrimaryUserAddress"][0]);
}
}
if (!found)
{
Console.WriteLine("Sad face");
}
}
catch (Exception x)
{
Console.WriteLine(x.Message);
}
Console.WriteLine("------------");
}
}
I was trying to figure out how to properly format a LDAP connection string last week, and found this entry over on serverfault:
How can I figure out my LDAP connection string?
I noticed you had a "/" between each OU or DC entry - I didn't include those in mine, and I don't see them included in the above example either.
I'm far from an expert (obviously) but just figured I would throw it out there.
I want to find out if the remote host has r/w access to a network share. To start out I wanted to see if I could query the target host's ability to query the UNC path for info, ala
var query = string.Format("select * from CIM_Directory where name = '{0}'", path);
This works fine for local files, e.g.
var path = #"c:\\Windows";
However, I can't figure out an appropriate way of querying a UNC path (e.g. \\foo\bar). The query always returns a blank set. I saw a related question about executing remote files and the solution for that one ended up being PsExec. I was hoping to ideally solve this problem entirely using WMI without having to rely on 3rd party execs, or uploading my own tool to the remote host.
Cheers
Here's a little usage sample of what I am trying to do right now (var values taken out):
using System;
using System.Linq;
using System.Management;
namespace netie
{
class Program
{
static void Main()
{
var connection = new ConnectionOptions
{
Username = "user",
Password = "pass",
Authority = "domain",
Impersonation = ImpersonationLevel.Impersonate,
EnablePrivileges = true
};
var scope = new ManagementScope("\\\\remote\\root\\CIMV2", connection);
scope.Connect();
var path = #"\\\\foo\\bar\\";
var queryString = string.Format("select * from CIM_Directory where name = '{0}'", path);
try
{
var query = new ObjectQuery(queryString);
var searcher = new ManagementObjectSearcher(scope, query);
foreach (var queryObj in searcher.Get().Cast<ManagementObject>())
{
Console.WriteLine("Number of properties: {0}", queryObj.Properties.Count);
foreach (var prop in queryObj.Properties)
{
Console.WriteLine("{0}: {1}", prop.Name, prop.Value);
}
Console.WriteLine();
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.ReadLine();
}
}
}
So it looks like this is basically impossible as WMI locks you out of network access for security reasons. Looks like your best bet is WinRM or PsExec for one-offs. You can potentially enable WinRM through WMI if that's your only path of access, but I imagine that ability can be blocked by group policies. The third option is to write your own Windows Service that will respond to requests and installing that through WMI if you have the access.
In short: the answer to my question is a No. Use WinRm, PsExec, or a custom win-service solution.
I know this is an old question, but for anyone looking to do this, the following code works. (I know that it's not WMI. Given the OP's answer I didn't even try it with WMI, but I shudder to think that people may write a service for something like this.)
if (System.IO.Directory.Exists(#"[SOME UNC PATH]"))
{
System.IO.DirectoryInfo info = new System.IO.DirectoryInfo(#"[SOME UNC PATH]");
var securityInfo = info.GetAccessControl();
var rules = securityInfo.GetAccessRules(
true,
true,
typeof(System.Security.Principal.SecurityIdentifier));
foreach (var rule in rules)
{
var fileSystemRule = rule as System.Security.AccessControl.FileSystemAccessRule;
if (ruleastype != null)
{
string user = fileSystemRule.IdentityReference.Translate(
typeof(System.Security.Principal.NTAccount)).Value;
System.Diagnostics.Debug.Print("{0} User: {1} Permissions: {2}",
fileSystemRule.AccessControlType.ToString(),
user,
fileSystemRule.FileSystemRights.ToString());
}
}
}
When run it produces the following output:
Allow User: Everyone Permissions: ReadAndExecute, Synchronize
Allow User: CREATOR OWNER Permissions: FullControl
Allow User: NT AUTHORITY\SYSTEM Permissions: FullControl
Allow User: BUILTIN\Administrators Permissions: FullControl
Allow User: BUILTIN\Users Permissions: ReadAndExecute, Synchronize
I try to get the name of the current logged in user in c# - not the account name which I could find easily in Environment.UserName.
I would like to enumerate the folders on MyComputer like explorer does it. How could I do that or is there another way to get the correct name of the user?
Thanks in advance.
Try using:
System.Security.Principal.WindowsIdentity.GetCurrent().Name This should return the account of the currently logged in user, and their name.
If that doesn't work after a username change, another method would be to get the current user's SID, then look up a username matching that SID.
using System.Security.Principal;
string sid = WindowsIdentity.GetCurrent().Owner.ToString();
return new SecurityIdentifier(sid).Translate(typeof(NTAccount)).ToString();
Failing this, take the SID and try and find a matching user either via WMI or via the registry. Instructions on how to do this manually are here: http://pcsupport.about.com/od/registry/ht/find-user-security-identifier.htm
If you can manually confirm that either of those methods return the NEW username, then just implement that in code, with either WMI calls or registry access.
Use it ,
string windowLoging = WindowsIdentity.GetCurrent().Name;
or
string windowsLogin = Page.User.Identity.Name;
or
string windowsLogin = Environment.GetEnvironmentVariable("USERNAME");
#damienc88
Your link leads me to the solution:
SelectQuery query = new SelectQuery("Win32_UserAccount", string.Format("Domain='{0}'", Environment.MachineName));
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
foreach (ManagementObject mObject in searcher.Get())
{
Console.WriteLine((string)mObject["Name"] + "\t" + (string)mObject["FullName"]);
}
"FullName" is the property which I've searched for. Thanks a lot. – Harald Pitro
I need to enumerate all user profiles on a local computer and list them in a combo box. Any special accounts need to be filtered out. I'm only concerned about actual user profiles on the computer where the app is running. I have done some searching but I haven't found a clear answer posted anywhere. I did find some code that might work but SelectQuery and ManagementObjectSearcher are displaying errors in VS and I'm not sure what I need to do to make this work.
using System.Management;
SelectQuery query = new SelectQuery("Win32_UserAccount");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
foreach (ManagementObject envVar in searcher.Get())
{
Console.WriteLine("Username : {0}", envVar["Name"]);
}
By saying "SelectQuery and ManagementObjectSearcher are displaying errors" I guess you didn't reference the System.Management dll.
You should right click References in your solution and add System.Management.
Then, with your using statement, the errors should disappear.
Anyway, including the error next time will assist everyone to help you :)
The mentioned code is great but when I tried on a machine connected to a Active Directory Domain all the usernames where returned for the domain. I was able to tweak the code a bit to only return the users that actually have a local directory on the current machine. If a better C# developer can refactor the code to make it cleaner - please help!
var localDrives = Environment.GetLogicalDrives();
var localUsers = new List<string>();
var query = new SelectQuery("Win32_UserAccount") { Condition = "SIDType = 1 AND AccountType = 512" };
var searcher = new ManagementObjectSearcher(query);
foreach (ManagementObject envVar in searcher.Get())
{
foreach (string drive in localDrives)
{
var dir = Path.Combine(String.Format("{0}Users", drive), envVar["name"].ToString());
if (Directory.Exists(dir))
{
localUsers.Add(envVar["name"].ToString());
}
}
}
Once you have the localUsers variable you can set this as the data source to your ComboBox control of our choice.
I am trying to get the list of local users of a computer using the following code.
internal void GetUsers()
{
try
{
List<string> adUsers = new List<string>();
DirectoryEntry directoryEntry = new DirectoryEntry("WinNT://" + Environment.MachineName);
foreach (DirectoryEntry child in directoryEntry.Children)
{
if (child.SchemaClassName.Equals("User", StringComparison.OrdinalIgnoreCase))
{
adUsers.Add(child.Name);
}
}
}
catch (Exception ex)
{
//Exception
}
}
This code works fine in my computer. However, when I tested it on a few other computers, the following system users were included in the list:
ASPNET,
HelpAssistant
Could some one throw some light on how I can get rid of these system users and get only users who actually log in, ie, normal users.
Thanks,
Ram
Not an answer as such, but some suggestions that might help.
I think the problem is that those accounts aren't real system accounts, so might not be so easy to distinguish.
You could look at the WMI classes Win32_UserAccount and Win32_UserProfile and see if there are any properties in there that might indicate which user accounts are normal ones and which ones are the ones you mention. Specifically, maybe the 'SIDType' or 'AccountType' properties of Win32_UserAccount or maybe the Special property of the Win32_UserProfile class.
Might be other WMI classes that might be worth looking at as well.
Or there might be some way that you can query if a user account has the interactive logon right (which I assume those two accounts might not have normally).
Have you tried enumerating the Properties collection on DirectoryEntry?
using (DirectoryEntry dirEntry = new DirectoryEntry(strchild))
{
foreach (string strPropertyName in dirEntry.Properties.PropertyNames)
{
Console.WriteLine(strPropertyName + " " + dirEntry.Properties[strPropertyName].Value.ToString());
}
}
Other than that, you may have to do an LDAP search on Active Directory to match the UserName you have found to an ActiveDirectory user.
Have a look at this article.
http://www.codeproject.com/KB/system/everythingInAD.aspx
Have fun.
The following code will get you the local users that actually have local accessible folders.
var localDrives = Environment.GetLogicalDrives();
var localUsers = new List<string>();
var query = new SelectQuery("Win32_UserAccount") { Condition = "SIDType = 1 AND AccountType = 512" };
var searcher = new ManagementObjectSearcher(query);
foreach (ManagementObject envVar in searcher.Get())
{
foreach (string drive in localDrives)
{
var dir = Path.Combine(String.Format("{0}Users", drive), envVar["name"].ToString());
if (Directory.Exists(dir))
{
localUsers.Add(envVar["name"].ToString());
}
}
}