I am using the following code for reading CPU Load on remote PC with Win XP. I have to use the credentials on the remote PC. It is working fine. But how can I use CIM session instead of WMI?
public void Read_CPU_Load_WMI()
{
WMI_path = "\\\\" + TagService.IP_to_Connect + "\\root\\cimv2";
System.Management.ConnectionOptions options = new System.Management.ConnectionOptions();
options.Username = username;
options.Password = password;
ManagementScope scope = new ManagementScope(WMI_path, options);
scope.Connect();
SelectQuery query = new SelectQuery("select PercentProcessorTime from Win32_PerfFormattedData_PerfOS_Processor where Name='_Total'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
foreach (ManagementObject queryObj in searcher.Get())
{
CPU_Load_WMI_int = Convert.ToInt16(queryObj["PercentProcessorTime"]);
CPU_Load_WMI_str = queryObj["PercentProcessorTime"].ToString();
}
}
I have started as following but cannot finish it
public void Read_CPU_Load_CIM
{
WMI_path = "\\\\" + TagService.IP_to_Connect + "\\root\\cimv2";
System.Management.ConnectionOptions options = new System.Management.ConnectionOptions();
options.Username = username;
options.Password = password;
string Namespace = #"root\cimv2";
string OSQuery = "SELECT * FROM Win32_PerfFormattedData_PerfOS_Processor where Name='_Total'";
CimSession mySession = CimSession.Create(WMI_path);
IEnumerable<CimInstance> queryInstance = mySession.QueryInstances(Namespace, "WQL", OSQuery);
//CPU_Load_WMI_int = ???
}
I'm writing a program that returns a list of users currently logged in a server.
Here's the code that does this:
private List<string> GetUsers(string server)
{
ConnectionOptions options = new ConnectionOptions();
ManagementScope moScope = new ManagementScope(#"\\" + server + #"\root\cimv2");
moScope.Connect();
ObjectQuery query = new ObjectQuery("select * from Win32_Process where name='explorer.exe'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(moScope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
{
ManagementOperationObserver mo = new ManagementOperationObserver();
mo.ObjectReady += new ObjectReadyEventHandler(mo_ObjectReady);
m.InvokeMethod(mo, "GetOwner", null);
}
}
private void mo_ObjectReady(object sender, ObjectReadyEventArgs e)
{
string user = e.NewObject.Properties["user"].Value.ToString();
//I would like to return the username back to the GetUsers function. How can I do this?
}
The mo_ObjectReady can get one username that is currently logged in the server. How could I return the value to the GetUsers function so I can put them altogether in a List?
Thanks in advance.
Is there any possibility to determine how a c# application was being started?
In my case I want to check if this application (wpf) is being started by a shortcut located in a specific folder.
So, there are two ways to open my application
using direct shortcut
starting another application which is like an update manager to keep my application up to date. After checking, it starts my application with Process.Start()
And I want to ensure that the application is only able to be started with the update manager.
A trick you could use is to check the parent's PID, and then get some of the parent's process information.
If the parent's process name is something like "explorer.exe" then the application was started from the shortcut or directly by double-clicking it on explorer.
Otherwise, it was started from another application: it could be your updater application, it could also be another application with the same name as your updater application...
This means you have to re-think how deep you want to go for such a solution, and how deep do you want security control. You could pass arguments from your updater to your main application, or implement some inter-process communication with token exchanges... it is impossible to make a 100% secure system.
As someone commented above, this seems like a XY problem... or maybe not. Maybe it is just a security concern. It's recommended to revise what exactly are you aiming for this software.
In case you need sample code for retrieving process information in .NET (by using System.Management), then just give a try to the code listed below. All you have to do is to place it in a console application project named 'Updater', and correctly set the path to your main application in the code.
If you play a little bit with this example by starting and closing YourApplication.exe in different situations, then you should be able to see an output like this:
Parent process 'Updater.exe' [PID=5472]
Parent process 'explorer.exe' [PID=12052]
The code below was tested on VS2017 .Net 4.6.1
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management;
class Program
{
static void Main(string[] args)
{
Process.Start(new ProcessStartInfo()
{
FileName = "YourApplication.exe" // path to your application
});
while (Console.ReadKey(true).Key != ConsoleKey.Escape)
{
Process process = Process.GetProcessesByName("YourApplication").FirstOrDefault(); // your application's process name
if (process == null)
{
Console.WriteLine($"Process is not running...");
continue;
}
ProcessManager pm = ProcessManager.FromLocalMachine();
var processProperties = pm.GetProcessProperties(process.Id);
int parentProcessId = Convert.ToInt32(processProperties[EProcessProperty.ParentProcessId]);
try
{
var parentProcessProperties = pm.GetProcessProperties(parentProcessId);
string parentProcessName = parentProcessProperties[EProcessProperty.Name].ToString();
Console.WriteLine($"Parent process '{parentProcessName ?? "Unknown"}' [PID={parentProcessId}]");
Console.WriteLine("---------------------------------");
}
catch { Console.WriteLine("Parent process information not found."); }
}
}
}
public class ProcessConnection
{
internal ManagementScope ManagementScope { get; }
internal ProcessConnection(string machineName, string user = null, string password = null, string domain = null)
{
ManagementScope = new ManagementScope
{
Path = new ManagementPath(#"\\" + machineName + #"\root\CIMV2"),
Options = new ConnectionOptions
{
Impersonation = ImpersonationLevel.Impersonate,
Authentication = AuthenticationLevel.Default,
EnablePrivileges = true,
Username = user == null ? null : (string.IsNullOrWhiteSpace(domain) ? user : $"{domain}\\{user}"),
Password = user == null ? null : password,
},
};
ManagementScope.Connect();
}
}
public class ProcessManager
{
public static ProcessManager FromLocalMachine() => new ProcessManager()
{
Machine = Environment.MachineName,
};
public static ProcessManager FromRemoteMachine(string machine, string user = null, string password = null, string domain = null) => new ProcessManager()
{
Machine = machine,
User = user,
Password = password,
Domain = domain,
};
private ProcessManager() { }
public string Machine { get; private set; }
public string User { get; private set; }
public string Password { get; private set; }
public string Domain { get; private set; }
private ProcessConnection Connection { get; set; }
private ManagementScope ManagementScope => Connection == null ? (Connection = new ProcessConnection(Machine, User, Password, Domain)).ManagementScope : Connection.ManagementScope;
public EProcessStartStatus StartProcess(string processPath)
{
ManagementClass mc = new ManagementClass($"\\\\{Machine}\\root\\CIMV2", "Win32_Process", null);
ManagementBaseObject process = mc.GetMethodParameters("Create");
process["CommandLine"] = processPath;
ManagementBaseObject createCode = mc.InvokeMethod("Create", process, null);
string createCodeStr = createCode["ReturnValue"].ToString();
return (EProcessStartStatus)Convert.ToInt32(createCodeStr);
}
public bool KillProcess(string processName)
{
try
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get()) mo.InvokeMethod("Terminate", null);
return true;
}
catch { return false; }
}
public bool KillProcess(int processId)
{
try
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ProcessId = '{processId}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get()) mo.InvokeMethod("Terminate", null);
return true;
}
catch { return false; }
}
public void SetProcessPriority(string processName, EProcessPriority priority)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject managementObject in managementObjectSearcher.Get())
{
ManagementBaseObject methodParams = managementObject.GetMethodParameters("SetPriority");
methodParams["Priority"] = priority;
managementObject.InvokeMethod("SetPriority", methodParams, null);
}
}
public string GetProcessOwner(string processName)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get())
{
ManagementBaseObject methodParams = mo.GetMethodParameters("GetOwner");
ManagementBaseObject owner = mo.InvokeMethod("GetOwner", null, null);
return owner["User"].ToString();
}
return null;
}
public string GetProcessOwnerSID(string processName)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get())
{
ManagementBaseObject methodParams = mo.GetMethodParameters("GetOwnerSid");
ManagementBaseObject OwnerSid = mo.InvokeMethod("GetOwnerSid", null, null);
return OwnerSid["Sid"].ToString();
}
return null;
}
public IList<int> GetRunningProcesses()
{
IList<int> processes = new List<int>();
SelectQuery query = new SelectQuery("SELECT * FROM Win32_Process");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get()) processes.Add(int.Parse(mo["ProcessId"].ToString()));
return processes;
}
public IDictionary<EProcessProperty, object> GetProcessProperties(int processId)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ProcessId = '{processId}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
Dictionary<EProcessProperty, object> properties = new Dictionary<EProcessProperty, object>();
foreach (ManagementObject mo in searcher.Get())
{
foreach (PropertyData pd in mo.Properties)
{
if (Enum.TryParse(pd.Name, out EProcessProperty e)) properties[e] = pd.Value;
else Console.WriteLine(pd.Name + " is not mapped in the properties enumeration.");
}
}
return properties;
}
public IDictionary<EProcessProperty, object> GetProcessProperties(string processName)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
Dictionary<EProcessProperty, object> properties = new Dictionary<EProcessProperty, object>();
foreach (ManagementObject mo in searcher.Get())
{
foreach (PropertyData pd in mo.Properties)
{
if (Enum.TryParse(pd.Name, out EProcessProperty e)) properties[e] = pd.Value;
else Console.WriteLine(pd.Name + " is not mapped in the properties enumeration.");
}
}
return properties;
}
public IList<int> GetProcessessFromExecutablePath(string executablePath)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ExecutablePath = '{executablePath.Replace("\\", "\\\\")}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
return searcher.Get().Cast<ManagementObject>().Select(mo => Convert.ToInt32(mo["ProcessId"])).ToList();
}
}
public enum EProcessPriority : uint
{
IDLE = 0x40,
BELOW_NORMAL = 0x4000,
NORMAL = 0x20,
ABOVE_NORMAL = 0x8000,
HIGH_PRIORITY = 0x80,
REALTIME = 0x100
}
public enum EProcessStartStatus
{
Success = 0,
AccessDenied = 2,
NoPermissions = 3,
Unknown = 8,
FileNotFound = 9,
Invalid = 21,
}
public enum EProcessProperty
{
Caption,
CommandLine,
CreationClassName,
CreationDate,
CSCreationClassName,
CSName,
Description,
ExecutablePath,
ExecutionState,
Handle,
HandleCount,
InstallDate,
KernelModeTime,
MaximumWorkingSetSize,
MinimumWorkingSetSize,
Name,
OSCreationClassName,
OSName,
OtherOperationCount,
OtherTransferCount,
PageFaults,
PageFileUsage,
ParentProcessId,
PeakPageFileUsage,
PeakVirtualSize,
PeakWorkingSetSize,
Priority,
PrivatePageCount,
ProcessId,
QuotaNonPagedPoolUsage,
QuotaPagedPoolUsage,
QuotaPeakNonPagedPoolUsage,
QuotaPeakPagedPoolUsage,
ReadOperationCount,
ReadTransferCount,
SessionId,
Status,
TerminationDate,
ThreadCount,
UserModeTime,
VirtualSize,
WindowsVersion,
WorkingSetSize,
WriteOperationCount,
WriteTransferCount,
}
If there are only 2 ways of starting your app, the second method should pass a parameter (a GUID?) to Process.Start() - generated by your updater app.
Maybe devise some kind of algorithm that allows the app to start only with the token.
From what I know this is impossible in the way you would like it to be but there's one trick which you can use. Firstly change your WPF application's entry method to get the command line arguments, and ( for example ) use -u argument to distinct from where the application was started. Then after -u you can pass a HWND or a process ID that matches your updater. Of course you have to then check if that application is running and if it's your updater.
example :
// updated process start
ProcessStartInfo psi = new ProcessStartInfo("your/WPF/application.exe");
psi.Arguments = "-u " + Process.GetCurrentProcess().Id;
// fill up rest of the properties you need
Process.Start(psi);
// wpf application's entry point
void Main(string[] args)
{
string updaterProcessIdstr = string.Empty;
for (int i = 0; i < args.Length; i++)
{
if(args[i] == "-u")
{
updaterProcessIdstr = args[i + 1];
i++;
}
}
int pid = int.Parse(updaterProcessIdstr);
Process updaterProcess = Process.GetProcessById(pid);
// do some validation here
// send something to stdin and read from stdout
// to determine if it was started from that updater.
}
Im trying to run a WMI query against another computer for errors within the last 5 hours or so. When running a WMI query, shouldnt you at least filter the initial query with a where clause?
Im basing my code off of samples generated from the WMI code creator on MSDN
Here is the select query im using
private ManagementScope CreateNewManagementScope(string server)
{
string serverString = #"\\" + server + #"\root\cimv2";
ManagementScope scope = new ManagementScope(serverString);
return scope;
}
ManagementScope scope = CreateNewManagementScope(servername);
scope.Connect();
SelectQuery query = new SelectQuery("select * from Win32_NtLogEvent where TimeWritten > '" + DateTime.Now.AddHours(-5).ToString() + "'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection logs = searcher.Get();
int iErrCount = logs.Count;
I just want to get a count of the errors in the last 5 hours. Its throwing an error when getting the count. The error is rather vague "Generic Failure".
[update - using date like this now]
DateTime d = DateTime.UtcNow.AddHours(-12);
string dateFilter = ManagementDateTimeConverter.ToDmtfDateTime(d);
SelectQuery query = new SelectQuery("select * from Win32_NtLogEvent where Logfile='Application' AND Type='Error' AND TimeWritten > '" + dateFilter + "'");
With the above code I get no results, yet I can see 2 errors in the event log. Whats wrong with the date filter?
Im using this example
http://msdn.microsoft.com/en-us/library/system.management.managementdatetimeconverter.todatetime.aspx
I did the following to get it to work. I hope this helps..
static void Main(string[] args)
{
var conOpt = new ConnectionOptions();
conOpt.Impersonation = ImpersonationLevel.Impersonate;
conOpt.EnablePrivileges = true;
conOpt.Username = "username";
conOpt.Password = "password";
conOpt.Authority = string.Format("ntlmdomain:{0}", "yourdomain.com");
var scope = new
ManagementScope(String.Format(#"\\{0}\ROOT\CIMV2",
"yourservername.yourdomain.com"),
conOpt);
scope.Connect();
bool isConnected = scope.IsConnected;
if (isConnected)
{
/* entire day */ string dateTime = getDmtfFromDateTime(DateTime.Today.Subtract(new TimeSpan(1, 0, 0, 0)));
string dateTime = getDmtfFromDateTime("09/06/2014 17:00:08"); // DateTime specific
SelectQuery query = new SelectQuery("Select * from Win32_NTLogEvent Where Logfile = 'Application' and TimeGenerated >='" + dateTime + "'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection logs = searcher.Get();
foreach (var log in logs)
{
Console.WriteLine("Message : {0}", log["Message"]);
Console.WriteLine("ComputerName : {0}", log["ComputerName"]);
Console.WriteLine("Type : {0}", log["Type"]);
Console.WriteLine("User : {0}", log["User"]);
Console.WriteLine("EventCode : {0}", log["EventCode"]);
Console.WriteLine("Category : {0}", log["Category"]);
Console.WriteLine("SourceName : {0}", log["SourceName"]);
Console.WriteLine("RecordNumber : {0}", log["RecordNumber"]);
Console.WriteLine("TimeWritten : {0}", getDateTimeFromDmtfDate(log["TimeWritten"].ToString()));
}
}
//ReadLog();
Console.ReadLine();
}
private static string getDmtfFromDateTime(DateTime dateTime)
{
return ManagementDateTimeConverter.ToDmtfDateTime(dateTime);
}
private static string getDmtfFromDateTime(string dateTime)
{
DateTime dateTimeValue = Convert.ToDateTime(dateTime);
return getDmtfFromDateTime(dateTimeValue);
}
private static string getDateTimeFromDmtfDate(string dateTime)
{
return ManagementDateTimeConverter.ToDateTime(dateTime).ToString();
}
This only helps kills processes on the local machine. How do I kill processes on remote machines?
You can use wmi. Or, if you don't mind using external executable, use pskill
I like this (similar to answer from Mubashar):
ManagementScope managementScope = new ManagementScope("\\\\servername\\root\\cimv2");
managementScope.Connect();
ObjectQuery objectQuery = new ObjectQuery("SELECT * FROM Win32_Process Where Name = 'processname'");
ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(managementScope, objectQuery);
ManagementObjectCollection managementObjectCollection = managementObjectSearcher.Get();
foreach (ManagementObject managementObject in managementObjectCollection)
{
managementObject.InvokeMethod("Terminate", null);
}
I use the following code. psKill is also a good way to go but sometimes you need to check the some other stuff, for example in my case remote machine was running multiple instances of same process but with different command line arguments, so following code worked for me.
ConnectionOptions connectoptions = new ConnectionOptions();
connectoptions.Username = string.Format(#"carpark\{0}", "domainOrWorkspace\RemoteUsername");
connectoptions.Password = "remoteComputersPasssword";
ManagementScope scope = new ManagementScope(#"\\" + ipAddress + #"\root\cimv2");
scope.Options = connectoptions;
SelectQuery query = new SelectQuery("select * from Win32_Process where name = 'MYPROCESS.EXE'");
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
{
ManagementObjectCollection collection = searcher.Get();
if (collection.Count > 0)
{
foreach (ManagementObject mo in collection)
{
uint processId = (uint)mo["ProcessId"];
string commandLine = (string) mo["CommandLine"];
string expectedCommandLine = string.Format("MYPROCESS.EXE {0} {1}", deviceId, deviceType);
if (commandLine != null && commandLine.ToUpper() == expectedCommandLine.ToUpper())
{
mo.InvokeMethod("Terminate", null);
break;
}
}
}
}