I'm having trouble connecting to remote computer to grab a list of processes running.
For my test machine I'm using the username #"ownme\veritas". The password is just "veritas".
The sample domain is "ownme".
return new System.Management.ConnectionOptions()
{
//certainly these variables have been checked and are correct
Username = UserCredential.DomainUser,
Password = UserCredential.Password
};
This is where I'm trying to do the connection. I don't know, but this might actually be the issue here. It could also be I didn't fill out enough fields in the ConnectionOptions above.
I referred to these two articles:
https://www.experts-exchange.com/questions/23514935/How-to-use-GetProcess-for-remote-sytems.html
https://msdn.microsoft.com/en-us/library/system.management.connectionoptions.authentication.aspx
I can't figure out what I'm doing wrong
ManagementScope scope = new ManagementScope($"\\\\{computer.DnsHostname}\\root\\cimv2", connectionOptions);
scope.Connect();
//Error: Access is denied
var processes = System.Diagnostics.Process.GetProcesses(dnsHostName);
GetProcesses will use the current users credentials to connect to the remote machine, not the credentials you specified via ConnectionOptions.
You need to use the WMI scope object that you created with the correct credentials to issue a query for the processes like this:
//..
SelectQuery query = new SelectQuery("select * from Win32_Process"); //query processes
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
{
using (ManagementObjectCollection collection = searcher.Get())
{
foreach (var process in collection) //loop through results
{
var name = process["name"]; //process name
//Do something with process
}
}
}
I didn't realize this was such a highly viewed question: I found the answer a long time ago. I actually didn't use WMI to do it. We actually filed a ticket with Microsoft and the discounted us for free after they gave us the answer. The answer is:
LogonUser + NEW_CREDENTIALS
Related
I am trying to figure out if the Active Directory Domain Services are installed a windows server.
I know they show up in the Server Manager, but can I programmatically get if the role is installed on a server using C# code
If you know the name of the server you want to test and can run the program with domain admin privileges remotely, you can use WMI:
internal static bool IsDomainController(string ServerName)
{
StringBuilder Results = new StringBuilder();
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("\\\\" + ServerName + "\\root\\CIMV2",
"SELECT * FROM Win32_ServerFeature WHERE ID = 10");
foreach (ManagementObject queryObj in searcher.Get())
{
Results.AppendLine(queryObj.GetPropertyValue("ID").ToString());
}
}
catch (ManagementException)
{
//handle exception
}
if (Results.Length > 0)
return true;
else
return false;
}
If you're running that locally on the server, the WMI path changes to:
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_ServerFeature WHERE ID = 10");
See the MSDN reference on Win32_ServerFeature for a full list of roles and their ID numbers.
If your question is to see if a server is a domain controller, you can enumerate the domain controllers in the domain and check the hostname of the server you are sitting on to see if it matches any of them. To get the list of domain controllers:
var domainControllers = new List<string>();
var domain = Domain.GetCurrentDomain();
foreach (var dc in domain.DomainControllers)
{
domainControllers.Add(dc.Name);
}
string whoami = Dns.GetHostname();
Make sure to add requisite error handling (like if you run this on a workgroup computer, it will die).
EDIT:
Alternate ways of detecting DCPROMO (because it's possible to install Domain Services without DCPROMO, and that is a bad thing):
1) Parse out (and check for the existence of) the debug log that is created when DCPROMO does its thing. Should be located at c:\windows\debug\dcpromo.log
2) This DSQUERY command is FAST and will give you all the servers where DCPROMO was ran:
dsquery * "cn=Sites,cn=Configuration,dc=MyDomain,dc=com" -Filter "(cn=NTDS Settings)" -attr distinguishedName whenCreated
Problem is getting that from command line output if you started it using Process. Working on a way to do this and will update once I have it tested, as I haven't done AD filtering in a query for a while.
From C# (.NET 4.0), we're making a WMI call like this:
var connectOptions = new ConnectionOptions
{
Authority = "ntlmdomain:" + paramValues.Domain,
Username = paramValues.UserName,
Password = paramValues.Password
};
var scopeString = #"\\" + paramValues.Server + #"\root\cimv2";
var scope = new ManagementScope(scopeString, connectOptions);
scope.Connect();
var queryString = String.Format("SELECT * FROM Win32_NTLogEvent WHERE LogFile = 'Security' AND TimeGenerated > '{0:yyyyMMddHHmm00.000000+0000}'";,
paramValues.StartTime);
var query = new ObjectQuery(queryString);
var searcher = new ManagementObjectSearcher(scope, query);
var queryCollection = searcher.Get();
This works fine, with the exception of a failure against only one of our servers. In that case, the searcher.Get() call hangs. Looking at the network traffic through Wireshark reveals that the Event Log entries are being correctly returned, but at some point the remote server simply terminates the TCP connection.
I found a WMI Tester utility online (http://www.paessler.com/tools/wmitester) that appears not to be written against the .NET framework (using DCOM). I can supply the same credentials and the same WMI query using that tool and get back the expected results.
Am I right to suspect that something is different between the .NET code and the DCOM call, or am I chasing the wrong thing? So far this is the only difference between the working and non-working code that I can find.
I am trying to get Server Network Protocol (SQL Server) using WMI.
I had written small application:
---------------------------C# code--------------------------
ManagementScope scope = new ManagementScope(#"\\computerName\root\Microsoft\SqlServer\ComputerManagement");
scope.Options.Username = "Administrator";
scope.Options.Password = "Password";
scope.Connect();
var query = new ObjectQuery(#"SELECT * FROM ServerNetworkProtocol");
var searcher = new ManagementObjectSearcher(scope, query);
var managementObjectCollection = searcher.Get();
var result = managementObjectCollection.Cast<ManagementObject>().ToList(); //<---- FileNotFoundException
var s = result.First()["ProtocolName"].ToString();
MessageBox.Show(String.Format("Protocol name: {0}", s));
And when I run the application, I will receive System.IO.FileNotFoundException.
I tested the query using WBEMTest Utility and everything is okey (with Administrator credentials).
Later I had written test service and put the same code, and service works correctly without any exceptions.
I suppose the problem related with credentials.
Can anyone explain more detailed what's wrong. What permissions need to run this query (if problem with credentials) and how I can resolve the issue.
I will be appreciated for any help.
just check credential and change one line :
ManagementScope scope = new ManagementScope(#"\\computerName\root\Microsoft\SqlServer\ComputerManagement10");
I have a Windows service which needs the currently logged username. I tried System.Environment.UserName, Windows identity and Windows form authentication, but all are returning "System" as the user my service is running as has system privileges. Is there a way to get the currently logged in username without changing my service account type?
This is a WMI query to get the user name:
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem");
ManagementObjectCollection collection = searcher.Get();
string username = (string)collection.Cast<ManagementBaseObject>().First()["UserName"];
You will need to add System.Management under References manually.
If you are in a network of users, then the username will be different:
Environment.UserName
Will Display format : 'Username',
rather than
System.Security.Principal.WindowsIdentity.GetCurrent().Name
Will Display format : 'NetworkName\Username'
Choose the format you want.
ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem") solution worked fine for me. BUT it does not work if the service is started over a Remote Desktop Connection.
To work around this, we can ask for the username of the owner of an interactive process that always is running on a PC: explorer.exe. This way, we always get the currently Windows logged-in username from our Windows service:
foreach (System.Management.ManagementObject Process in Processes.Get())
{
if (Process["ExecutablePath"] != null &&
System.IO.Path.GetFileName(Process["ExecutablePath"].ToString()).ToLower() == "explorer.exe" )
{
string[] OwnerInfo = new string[2];
Process.InvokeMethod("GetOwner", (object[])OwnerInfo);
Console.WriteLine(string.Format("Windows Logged-in Interactive UserName={0}", OwnerInfo[0]));
break;
}
}
Modified code of Tapas's answer:
Dim searcher As New ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem")
Dim collection As ManagementObjectCollection = searcher.[Get]()
Dim username As String
For Each oReturn As ManagementObject In collection
username = oReturn("UserName")
Next
Just in case someone is looking for user Display Name as opposed to User Name, like me.
Here's the treat :
System.DirectoryServices.AccountManagement.UserPrincipal.Current.DisplayName.
Add Reference to System.DirectoryServices.AccountManagement in your project.
Try WindowsIdentity.GetCurrent(). You need to add reference to System.Security.Principal
You can also try
System.Environment.GetEnvironmentVariable("UserName");
Completing the answer from #xanblax
private static string getUserName()
{
SelectQuery query = new SelectQuery(#"Select * from Win32_Process");
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
{
foreach (System.Management.ManagementObject Process in searcher.Get())
{
if (Process["ExecutablePath"] != null && string.Equals(Path.GetFileName(Process["ExecutablePath"].ToString()), "explorer.exe", StringComparison.OrdinalIgnoreCase))
{
string[] OwnerInfo = new string[2];
Process.InvokeMethod("GetOwner", (object[])OwnerInfo);
return OwnerInfo[0];
}
}
}
return "";
}
I need to check a group of servers to see whether the anti virus is up-to-date and running. Tricky thing is that they are spread over Windows 2003 and 2008 servers and I need to be able to check them all.
Is there any way of doing this with C# or VB.NET?
I have briefly looked around using WMI, but it appears on 2008/win7 computers Microsoft has changed what information they give back to you.
In summary, I need the following:
AV name
AV version
AV Up-to-Date
AV Enabled/Running
Can anyone help?
Sample can be found here using WMI as you mentioned. The poster states this is being done on a Win 7 machine; so the code below should get you started...
ConnectionOptions _connectionOptions = new ConnectionOptions();
//Not required while checking it in local machine.
//For remote machines you need to provide the credentials
//options.Username = "";
//options.Password = "";
_connectionOptions.EnablePrivileges = true;
_connectionOptions.Impersonation = ImpersonationLevel.Impersonate;
//Connecting to SecurityCenter2 node for querying security details
ManagementScope _managementScope = new ManagementScope(string.Format("\\\\{0}\\root\\SecurityCenter2", ipAddress), _connectionOptions);
_managementScope.Connect();
//Querying
ObjectQuery _objectQuery = new ObjectQuery("SELECT * FROM AntivirusProduct");
ManagementObjectSearcher _managementObjectSearcher =
new ManagementObjectSearcher(_managementScope, _objectQuery);
ManagementObjectCollection _managementObjectCollection = _managementObjectSearcher.Get();
if (_managementObjectCollection.Count > 0)
{
foreach (ManagementObject item in _managementObjectCollection)
{
Console.WriteLine(item["displayName"]);
//For Kaspersky AntiVirus, I am getting a null reference here.
//Console.WriteLine(item["productUptoDate"]);
//If the value of ProductState is 266240 or 262144, its an updated one.
Console.WriteLine(item["productState"]);
}
}
Depending on how your environment is setup you may need to specify your security and permissions. You should also note that some antivirus products (like McAfee) do not make data available through WMI.
You can query the Antivirus information from WMI using this snippet:
string computer = Environment.MachineName;
string wmipath = #"\\" + computer + #"\root\SecurityCenter";
string query = #"SELECT * FROM AntivirusProduct";
ManagementObjectSearcher searcher = new ManagementObjectSearcher(wmipath, query);
ManagementObjectCollection results = searcher.Get();
foreach (ManagementObject result in results)
{
// do something with `result[value]`);
}