I'm trying to terminate a process on a remote machine with WMI / C# on .NET 4.5. In the code below, when the Get method is called on the ManagementObjectSearcher instance nothing is returned, so the line inside the foreach is not reached. The ManagementScope is connected and the query variable contains the name of the process for termination.
Thx for any help.
try
{
ConnectionOptions connOptions = new ConnectionOptions();
connOptions.Impersonation = ImpersonationLevel.Impersonate;
connOptions.EnablePrivileges = true;
ManagementScope manScope = new ManagementScope(String.Format(#"\\{0}\ROOT\CIMV2", NetworkName), connOptions);
manScope.Connect();
var query = new SelectQuery("select * from Win32_process where name = '" + ProcessName + "'");
using (var searcher = new ManagementObjectSearcher(manScope, query))
{
foreach (ManagementObject process in searcher.Get())
{
process.InvokeMethod("Terminate", null);
}
}
}
catch (ManagementException err)
{
//Do something with error message here
}
As outlined in my comment above, for completeness here's the code with my changes that are as follows.
try
{
ConnectionOptions connOptions = new ConnectionOptions();
connOptions.Impersonation = ImpersonationLevel.Impersonate;
connOptions.EnablePrivileges = true;
ManagementScope manScope = new ManagementScope(String.Format(#"\\{0}\ROOT\CIMV2", NetworkName), connOptions);
manScope.Connect();
ProcessName = ProcessName + ".exe";
using (var searcher = new ManagementObjectSearcher(manScope, new SelectQuery("select * from Win32_Process where Name = '" + ProcessName + "'")))
{
foreach (ManagementObject process in searcher.Get())
{
process.InvokeMethod("Terminate", null);
}
}
}
catch (ManagementException err)
{
//Do something with error message here
}
In my case i was unable to receive CPU utilization value remotely using WMI query:
SELECT PercentProcessorTime FROM Win32_PerfFormattedData_PerfOS_Processor WHERE Name='_Total'
I changed project build platform target from Any CPU to x64 to match my system bitness, and problem was solved. Another way is uncheck Prefer 32-bit checkbox when Any CPU is selected.
Use the Count property to check, whether it contains any record. That is, if(searcher.Get().count == 0) returns true, means no record is present.
Related
I am attempting to execute a .bat file on a remote machine (a server) that ends a process and kicks the user out of a database system. When executed on the server, the file works correctly and ends the process on the client machine.
However, when executed through C#, the command is entered into the command prompt and cannot execute. Here is the .bat file;
psexec \\lp-100 msg * Hi Dan - your being removed!
pskill \\lp-100 sdcdatabase.vshost.exe
pause
The issue arises when executed in C#, this is the error message:
What this leads me to believe is that actually the .bat file is not being executed on the server (that does have PsTools installed), but instead the contents is being copied over and executed on the client machine instead.
Here is the code I am using to execute the .bat file;
Process proc = null;
try
{
string batDir = string.Format(#"\\hqdb1\sdc_sqldb\pstools\");
proc = new Process();
proc.StartInfo.WorkingDirectory = batDir;
proc.StartInfo.FileName = "removeuser.bat";
proc.StartInfo.CreateNoWindow = false;
proc.Start();
proc.WaitForExit();
MessageBox.Show("Bat file executed !!");
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace.ToString());
}
Is this executing the .bat file on the server, kicking the client off, or executing on the client and not finding PsTools?
Years ago I wrote this code, try if it's still working:
ConnectionOptions options = new ConnectionOptions();
options.Password = args[2];
options.Username = args[1];
string machine= args[0];
ManagementScope scope = new ManagementScope();
scope.Options = options;
scope.Path = new ManagementPath(#"\\" + machine + #"\root\cimv2");
scope.Connect();
ObjectQuery query = new ObjectQuery("Select * from Win32_Process Where Name = '" + args[3] + "'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
{
object y = m.GetPropertyValue("ProcessID");
int pID = Convert.ToInt32(y);
m.InvokeMethod("Terminate", null);
}
I want to create and delete a file on a remote machine of which i have admin username and password.
I am using this code
ConnectionOptions options = new ConnectionOptions();
options.Username = "admin";
options.Password = "12345";
ManagementScope scope = null;
ObjectQuery query = null;
ManagementObjectSearcher searcher = null;
try
{
scope = new ManagementScope(#"\\192.168.3.125\root\CIMV2", options);
scope.Connect();
query = new ObjectQuery(#"SELECT * FROM CIM_Datafile WHERE name = 'c:\\c$\\Testing\\Test.txt'");
searcher = new ManagementObjectSearcher(scope, query); // EDIT forgot to include 'scope' previously
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
foreach(ManagementObject mo in searcher.Get())
{
uint returnCode = (uint)mo.InvokeMethod("Delete", null);
if (returnCode == 0)
Console.WriteLine("File was successfully deleted");
else
Console.WriteLine("Deletion failed due to return code " + returnCode);
}
But it is giving me invalid query error and also i want to know how to Create a file on Remote machine.
and i even cant access the path \\192.168.3.125\C$\Testing\Test.txt
My file location is c:\Testing\Test.txt
Firstly can you access the file via the windows explorer from the machine (start -> run -> \192.168.3.125\C$\Testing\Test.txt)
If so what's wrong with
File.Delete(#"\\192.168.3.125\C$\Testing\Test.txt");
In my case, when I was connecting two windows based computers, you could just put:
#"\\PC-NAME\NEXT-FOLDER\NEXT-FOLDER\test.txt"
So far my code will start a process (Install an application) with command line arguments on a target computer and wait for the process to finish, IF I copy the install files to that computer.
My goal now is to:
Start a process with command line arguments (Install an application) on the remote computer.
NOT copy the files to the remote computer. The installer files will be located on a network share that both the sender computer and the remote computer have access to.
Wait for the process to finish.
Any help is much appreciated!
private void StartAppAction(string PCName, string Params)
{
//Example of Params \\Server\Folder\Application.EXE /s
ConnectionOptions conn = new ConnectionOptions();
conn.Impersonation = ImpersonationLevel.Impersonate;
conn.Authentication = AuthenticationLevel.Default;
conn.EnablePrivileges = true;
ManagementScope manScope = new ManagementScope(String.Format(#"\\{0}\ROOT\CIMV2", PCName), conn);
try
{
manScope.Connect();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
ObjectGetOptions objOpt = new ObjectGetOptions();
ManagementPath manPath = new ManagementPath("Win32_Process");
ManagementClass manClass = new ManagementClass(manScope, manPath, objOpt);
ManagementBaseObject inParams = manClass.GetMethodParameters("Create");
inParams["CommandLine"] = Params;
ManagementBaseObject outParams = manClass.InvokeMethod("Create", inParams, null);
string query = String.Format("SELECT * FROM __InstanceDeletionEvent WITHIN 3 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.ProcessID = '{0}'", outParams["ProcessId"].ToString());
string scope = #"\\" + PCName + #"\root\CIMV2";
EventWatcherOptions evOp = new EventWatcherOptions(null, new TimeSpan(1, 0, 0), 1);
ManagementEventWatcher manWatch = new ManagementEventWatcher(scope, query, evOp);
try
{
ManagementBaseObject watcher = manWatch.WaitForNextEvent();
var ID = ((ManagementBaseObject)watcher["TargetInstance"]);
//Process Ended
}
catch
{
MessageBox.Show("Unable to watch for the remote process to finish");
}
}
public ManagementScope GetScope()
{
try
{
//string classScope="winmgmts:" + "{impersonationLevel=impersonate}!\\" + strComputer + "\\root\\cimv2";
string serverString = #"root\cimv2";
ManagementScope scope = new ManagementScope(serverString);
ConnectionOptions options = new ConnectionOptions
{
Impersonation = ImpersonationLevel.Impersonate,
Authentication = AuthenticationLevel.Connect,
EnablePrivileges = true
};
scope.Options = options;
return scope;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
public void InvokeMethodsFunctions1()
{
ManagementScope mScope = GetScope();
mScope.Connect();
if (mScope.IsConnected)
{
ManagementClass processClass =
new ManagementClass(mScope.Path);
ManagementObjectSearcher mos = new ManagementObjectSearcher(mScope, new ObjectQuery("SELECT * FROM Win32_Product"));
//get collection of WMI objects
ManagementObjectCollection queryCollection = mos.Get();
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"Result.txt"))
{
textBox1.Text = "";
//enumerate the collection.
foreach (ManagementObject m in queryCollection)
{
// access properties of the WMI object
string line = " " + m["Name"] + " , InstallDate : " + m["InstallDate"] + " LocalPackage : " + m["LocalPackage"];
Console.WriteLine(line);
file.WriteLine(line);
textBox1.Text += line + "\n";
}
}
}
}
So whats wrong in my Code ?
There is nothing wrong , the Win32_Product WMI class only list the products installed by the Windows Installer (MSI).
I just tested the following, simplified version of your code and I see everything installed on my pc, even services I wrote and installed myself:
var products = new ManagementObjectSearcher(new ObjectQuery("SELECT * FROM Win32_Product"));
var result = products.Get();
foreach (var product in result)
{
Console.WriteLine(product.GetPropertyValue("Name").ToString());
}
Console.ReadLine();
It looks like you are narrowing your query by scope, which is possibly why you aren't seeing everything, try the above and see if you have more luck.
I have tried two ways to accomplish this so far.
The first way, I used System.Diagnostics, but I get a NotSupportedException of "Feature is not supported for remote machines" on the MainModule.
foreach (Process runningProcess in Process.GetProcesses(server.Name))
{
Console.WriteLine(runningProcess.MainModule.FileVersionInfo.FileDescription);
}
The second way, I attempted using System.Management but it seems that the Description of the ManagementObject is the she same as the Name.
string scope = #"\\" + server.Name + #"\root\cimv2";
string query = "select * from Win32_Process";
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection collection = searcher.Get();
foreach (ManagementObject obj in collection)
{
Console.WriteLine(obj["Name"].ToString());
Console.WriteLine(obj["Description"].ToString());
}
Would anyone happen to know of a better way to go about getting the descriptions of a running process on a remote machine?
Well I think I've got a method of doing this that will work well enough for my purposes. I'm basically getting the file path off of the ManagementObject and getting the description from the actual file.
ConnectionOptions connection = new ConnectionOptions();
connection.Username = "username";
connection.Password = "password";
connection.Authority = "ntlmdomain:DOMAIN";
ManagementScope scope = new ManagementScope(#"\\" + serverName + #"\root\cimv2", connection);
scope.Connect();
ObjectQuery query = new ObjectQuery("select * from Win32_Process");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection collection = searcher.Get();
foreach (ManagementObject obj in collection)
{
if (obj["ExecutablePath"] != null)
{
string processPath = obj["ExecutablePath"].ToString().Replace(":", "$");
processPath = #"\\" + serverName + #"\" + processPath;
FileVersionInfo info = FileVersionInfo.GetVersionInfo(processPath);
string processDesc = info.FileDescription;
}
}