I am trying to create an application that pulls process information and puts it into a SQL table.
I am pulling Process Name, PID, CPU Time, Memory Usage, Page, and Handles.
Everything works fine except for the CPU Time. Here is the code I am using to get the CPU information:
Process[] processes = Process.GetProcesses(machineName);
foreach (Process p in processes)
{
var cpuTime = p.TotalProcessorTime;
}
However I am getting this error:
Feature is not supported for remote machines.
Does anyone have any other way I can get this information and still be able to add it to my SQL table?
How about using WMI ?
string computerName="MyPc";
System.Management.ManagementScope ms = new System.Management.ManagementScope(#"\\" + computerName + #"\root\cimv2");
System.Management.SelectQuery sq = new System.Management.SelectQuery("SELECT * FROM Win32_Process");
System.Management.ManagementObjectSearcher mos = new System.Management.ManagementObjectSearcher(ms,sq);
foreach (System.Management.ManagementObject mo in mos.Get())
{
Console.WriteLine(mo["Name"].ToString());
}
Console.Read();
Related
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
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.
My user is in the Administrators group. I am using the .NET WMI API (System.Management) to kill a process using this code:
var scope = new ManagementScope("\root\cimv2");
scope.Connect();
var query = new ObjectQuery(
string.Format("Select * from Win32_Process Where ProcessID = {0}",
processId));
var searcher = new ManagementObjectSearcher(scope, query);
var coll = searcher.Get().GetEnumerator();
coll.MoveNext();
var mgmtObj = (ManagementObject)coll.Current;
var ret = (uint) mgmtObj.InvokeMethod("Terminate");
// ret == 2 here, meaning "Access Denied"
It's failing to kill the process and returning a 2 (Access Denied). However if I use:
Process.Start("cmd", string.Format("/c \"taskkill /f /pid {0}\"", processId));
the process gets killed. (but if I leave out /f it fails).
Is there any way to terminate the process using WMI?
EDIT: I found the following on
http://msdn.microsoft.com/en-us/library/windows/desktop/aa393907(v=vs.85).aspx:
To terminate a process that you do not own, enable the
SeDebugPrivilege privilege.
The page provides VBScript code but how would I do this in C#?
That is only possible with some API calls which are only available via pinvoke - for complete C# source code see here.
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]`);
}
I am doing a query for all the users on the machine and when it executes it grabs 100% CPU and locks up the system. I have waited up to 5 minutes and nothing happens.
In the Task Manager wmiprvse.exe is using all the CPU. When I kill that process everything returns to normal.
Here is my code:
SelectQuery query = new SelectQuery("Win32_UserAccount",
"LocalAccount=1 and Domain='" + GetMachine().DomainName + "'");
using(ManagementObjectSearcher searcher = new ManagementObjectSearcher(query)) {
IList<WindowsUser> users = new List<WindowsUser>();
Console.WriteLine("Getting users...");
foreach (ManagementObject envVar in searcher.Get()) {
Console.WriteLine("Getting " + envVar["Name"].ToString() + "...");
}
}
In the console all I see is Getting users... and nothing else. The problem appears to be with searcher.Get().
Does anyone know why this query is taking 100% CPU? Thanks.
EDIT: OK I found that it the WMI process is only eating 25% CPU but it doesn't get released if I end the program (the query never finishes). The next time I start an instance the process goes up to 50% CPU, etc, etc until it is at 100%.
So my new question is why is the CPU not getting released and how long should a query like this take to complete?
Try this
SelectQuery query = new SelectQuery("Win32_UserAccount", "LocalAccount=1 and Domain='" + GetMachine().DomainName + "'");
using(ManagementObjectSearcher searcher = new ManagementObjectSearcher(query)) {
IList<WindowsUser> users = new List<WindowsUser>();
Console.WriteLine("Getting users...");
ManagementObjectCollection myCollection = searcher.Get();
foreach (ManagementObject envVar in MyCollection){
Console.WriteLine("Getting " + envVar["Name"].ToString() + "...");
}
}