I am trying to find the executable path of a running service , and i have looked upon ServiceBase and there is no property indicating the path. Nor does ServiceController offer any kind of help.
ServiceBase []services=ServiceController.GetServices();
IEnumerable<string> paths=services.Select(x=> x. ? );
I have also tried using sc qc cmd command but it seems it does not work for a particular service
Process proc = new Process();
var info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.Arguments = "sc qc \"[service-name]\" | find \"BINARY_PATH_NAME\"";
proc.StartInfo = info;
proc.Start();
var data = await proc.StandardOutput.ReadToEndAsync();
It throws the error:
System.InvalidOperationException: 'StandardOut has not been redirected
or the process hasn't started yet.'
Is there any way to get the path of the executable for a particular service or all of them ?
You can use WMI
For example (with WMI Code Creator):
try
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_Service");
foreach (ManagementObject queryObj in searcher.Get())
{
Console.WriteLine("DisplayName: {0}", queryObj["DisplayName"]);
Console.WriteLine("Name: {0}", queryObj["Name"]);
Console.WriteLine("PathName: {0}", queryObj["PathName"]);
Console.WriteLine("ProcessId: {0}", queryObj["ProcessId"]);
Console.WriteLine("-----------------------------------");
}
}
catch (ManagementException me)
{
MessageBox.Show("An error occurred while querying for WMI data: " + me.Message);
}
Related
How to identify the hardware details of a Linux/Mac machine using.Net Core.
For windows machines, we can use System.Management and WMI Query.
So is there any similar way to identify the hardware details (like RAM ,Processor,Monitor ,CAM etc) of Linux and Mac machines.
For windows, I'm using:
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("select * from Win32_Processor");
This is a piece of code to write bash linux commends in .net core:
using System;
using System.Diagnostics;
public static class ShellHelper
{
public static string Bash(this string cmd)
{
var escapedArgs = cmd.Replace("\"", "\\\"");
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = $"-c \"{escapedArgs}\"",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
string result = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return result;
}
}
This is an extension method, you use it like this:
var output = "ps aux".Bash();
As for the commends, refer the Get Linux System and Hardware Details on the Command Line article on VITUX to help you out writing the commends, it lists most of the commends to collect system information on Linux.
For MAC:
System.Management.ManagementClass mc = default(System.Management.ManagementClass);
ManagementObject mo = default(ManagementObject);
mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection moc = mc.GetInstances();
foreach (var mo in moc) {
if (mo.Item("IPEnabled") == true) {
Adapter.Items.Add("MAC " + mo.Item("MacAddress").ToString());
}
}
I have done a workaround to get hardware info as per Platform. For windows I have used old way of system Management classes, for Linux i have used different Bash commands to Get Processor Id, Model,model version,machine id.
Following are some linux commands i am using
1. "LinuxModel": "cat /sys/class/dmi/id/product_name"
2. "LinuxModelVersion": "cat /sys/class/dmi/id/product_version"
3. "LinuxProcessorId": "dmidecode -t processor | grep -E ID | sed 's/.*: //' | head -n 1"
4. "LinuxFirmwareVersion": "cat /sys/class/dmi/id/bios_version",
5. "LinuxMachineId": "cat /var/lib/dbus/machine-id"
Waiting for some support in the .net core framework soon
My gihub post address is https://github.com/dotnet/corefx/issues/22660
I have also used similar extension method with a bit optimized code for bash command
public static string Bash(this string cmd)
{
string result = String.Empty;
try
{
var escapedArgs = cmd.Replace("\"", "\\\"");
using (Process process = new Process())
{
process.StartInfo = new ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = $"-c \"{escapedArgs}\"",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
};
process.Start();
result = process.StandardOutput.ReadToEnd();
process.WaitForExit(1500);
process.Kill();
};
}
catch (Exception ex)
{
//Logger.ErrorFormat(ex.Message, ex);
}
return result;
}
I found this code on an old thread to shutdown the local machine:
using System.Management;
void Shutdown()
{
ManagementBaseObject mboShutdown = null;
ManagementClass mcWin32 = new ManagementClass("Win32_OperatingSystem");
mcWin32.Get();
// You can't shutdown without security privileges
mcWin32.Scope.Options.EnablePrivileges = true;
ManagementBaseObject mboShutdownParams =
mcWin32.GetMethodParameters("Win32Shutdown");
// Flag 1 means we want to shut down the system. Use "2" to reboot.
mboShutdownParams["Flags"] = "1";
mboShutdownParams["Reserved"] = "0";
foreach (ManagementObject manObj in mcWin32.GetInstances())
{
mboShutdown = manObj.InvokeMethod("Win32Shutdown",
mboShutdownParams, null);
}
}
Is it possible to use a similar WMI method to reboot flag "2" a remote machine, for which i only have machine name, not IPaddress.
EDIT: I currently have:
SearchResultCollection allMachinesCollected = machineSearch.FindAll();
Methods myMethods = new Methods();
string pcName;
ArrayList allComputers = new ArrayList();
foreach (SearchResult oneMachine in allMachinesCollected)
{
//pcName = oneMachine.Properties.PropertyNames.ToString();
pcName = oneMachine.Properties["name"][0].ToString();
allComputers.Add(pcName);
MessageBox.Show(pcName + "has been sent the restart command.");
Process.Start("shutdown.exe", "-r -f -t 0 -m \\" + pcName);
}
but this doesn't work, and I would prefer WMI going forward.
To address WMI queries to a remote computer, you simply specify that computer's name (or IP address) in the ManagementScope object.
I'm not well up in C#, but here's an example I came up with using MSDN and WMI Code Creator (which is, by the way, an excellent tool for generating WMI code, and supports C# among others). Hope this code will give you the idea.
(Disclaimer: This code is untested.)
using System;
using System.Management;
...
void Shutdown()
{
try
{
const string computerName = "COMPUTER"; // computer name or IP address
ConnectionOptions options = new ConnectionOptions();
options.EnablePrivileges = true;
// To connect to the remote computer using a different account, specify these values:
// options.Username = "USERNAME";
// options.Password = "PASSWORD";
// options.Authority = "ntlmdomain:DOMAIN";
ManagementScope scope = new ManagementScope(
"\\\\" + computerName + "\\root\\CIMV2", options);
scope.Connect();
SelectQuery query = new SelectQuery("Win32_OperatingSystem");
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(scope, query);
foreach (ManagementObject os in searcher.Get())
{
// Obtain in-parameters for the method
ManagementBaseObject inParams =
os.GetMethodParameters("Win32Shutdown");
// Add the input parameters.
inParams["Flags"] = 2;
// Execute the method and obtain the return values.
ManagementBaseObject outParams =
os.InvokeMethod("Win32Shutdown", inParams, null);
}
}
catch(ManagementException err)
{
MessageBox.Show("An error occurred while trying to execute the WMI method: " + err.Message);
}
catch(System.UnauthorizedAccessException unauthorizedErr)
{
MessageBox.Show("Connection error (user name or password might be incorrect): " + unauthorizedErr.Message);
}
}
I had trouble with this also. WMI can be misleading with methods for classes and object. My solution is for rebooting a host on the network with C# and WMI, but is easily simplified for local machine:
private void rebootHost(string hostName)
{
string adsiPath = string.Format(#"\\{0}\root\cimv2", hostName);
ManagementScope scope = new ManagementScope(adsiPath);
// I've seen this, but I found not necessary:
// scope.Options.EnablePrivileges = true;
ManagementPath osPath = new ManagementPath("Win32_OperatingSystem");
ManagementClass os = new ManagementClass(scope, osPath, null);
ManagementObjectCollection instances;
try
{
instances = os.GetInstances();
}
catch (UnauthorizedAccessException exception)
{
throw new MyException("Not permitted to reboot the host: " + hostName, exception);
}
catch (COMException exception)
{
if (exception.ErrorCode == -2147023174)
{
throw new MyException("Could not reach the target host: " + hostName, exception);
}
throw; // Unhandled
}
foreach (ManagementObject instance in instances)
{
object result = instance.InvokeMethod("Reboot", new object[] { });
uint returnValue = (uint)result;
if (returnValue != 0)
{
throw new MyException("Failed to reboot host: " + hostName);
}
}
}
You can use shutdown command if you need an non-WMI solution.
shutdown [{-l|-s|-r|-a}] [-f] [-m [\\ComputerName]] [-t xx] [-c "message"] [-d[u][p]:xx:yy]
Use the -m for shutting the remote machine.
Refer this link for more info.
http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/shutdown.mspx
this will work like sharm
gwmi win32_operatingsystem -ComputerName xxxxxxxxxxxx | Invoke-WmiMethod -Name reboot
I have a process a method that successfully stops the process. But how can I start it? It is a .exe file that lays on the remote machines harddrive.
var ui = new ImpersonateUser();
var processName = "notepad.exe";
object[] processArgs = { #"C:\\WINDOWS\notepad.exe" };
try
{
ui.Impersonate(Domain, _userName, _pass);
ManagementPath path = new ManagementPath
{
Server = "serverName",
NamespacePath = "\\ROOT\\CIMV2",
ClassName = "Win32_Process"
};
ManagementScope scope = new ManagementScope(path);
ManagementClass management = new ManagementClass(path);
var query = new SelectQuery("SELECT * from Win32_process WHERE name = '" + processName + "'");
using (var searcher = new ManagementObjectSearcher(scope, query))
{
foreach (ManagementObject process in searcher.Get())
{
process.InvokeMethod("Terminate", null); //This work
Thread.Sleep(3000);
management.InvokeMethod("Create", processArgs); //doesnt work. Why ?
}
}
}
How can I make the .exe start after I have shut it down?
You have a typo (D instead of T) in a program name. It should be noTepad.exe and not noDepad.exe Besides I suggest to check results returned by InvokeMethod In your case it returns 9 what means Path Not Found. Here is a full list of codes.
UPDATE
If InvokeMethod returns 0 but you don't see a new instance of notepad on a remote machine it means that it was run in background. However, you should be able to see this new instance in Windows Task Manager.
I am trying to get a java Process object by using C#.
The thing is i have several java Processes running on my computer.
Following is the way i chose to get Processes:
Process[] processes = Process.GetProcessesByName("java");
foreach(Process proc in processes){
//I need a filter here to get the correct process.
}
The java Process is also controlled by my C# program as below:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = javahome + "\\bin\\java.exe";
startInfo.Arguments = "-jar Example.jar port=88888";
startInfo.WorkingDirectory = "\\testFolder";
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
Process proc = new Process();
proc.StartInfo = startInfo;
proc.Start();
What i want is go through the array of Process to check which one has the same Arguments with the Process object that i started in another program.
But the problem is when i did like this:
Console.WriteLine(proc.StartInfo.Arguments);
I found there is nothing in it, even i know it is the process that i started in another program. This confused me a lot.
Does anyone know this issue?
You can't do it that way. When you start a process keep the handler for that process in a dictionary where the value is the process arguments, that's the only way I see for you to archive that.
Dictionary<IntPtr, string> processArguments = new Dictionary<IntPtr,string>();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = javahome + "\\bin\\java.exe";
startInfo.Arguments = "-jar Example.jar port=88888";
startInfo.WorkingDirectory = "\\testFolder";
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
Process proc = new Process();
proc.StartInfo = startInfo;
proc.Start();
processArguments.Add(proc.Handle, javahome + "\\bin\\java.exe");
....
Process[] processes = Process.GetProcessesByName("java");
foreach (Process proc in processes)
{
var arguments = processArguments.Where(x => x.Key.Equals(proc.Handle)).FirstOrDefault().Value;
}
You can try like this by using LINQ as below :
Process[] processes = Process.GetProcessesByName("java");
var fileteredProcess = from pro in processes
where (pro.StartInfo.WorkingDirectory == "workingDIR") &&
(pro.StartInfo.Arguments == "Arguments")
select pro;
foreach (var proc in fileteredProcess)
{
}
Here is an alternative solution using WMI:
Process[] processes;
Process selectedProc = null;
int selectedProcId = 0;
// http://wutils.com/wmi/
// using System.Management;
ManagementScope scope = new ManagementScope("\\\\.\\ROOT\\cimv2");
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_Process "
+ "WHERE Name = 'java.exe'");
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(scope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
{
// access properties of the WMI object
Console.WriteLine("CommandLine : {0}", m["CommandLine"]);
Console.WriteLine("ProcessId : {0}", m["ProcessId"]);
if (m["CommandLine"].ToString().Contains("my pattern"))
{
selectedProcId = int.Parse(m["ProcessId"].ToString());
selectedProc = Process.GetProcessById(selectedProcId);
break;
}
}
if (selectedProc != null)
{
Console.WriteLine("Proc title {0}", selectedProc.MainWindowTitle);
}
I'm working on an application which scans a given networkrange for computers. From the found clients I need to get the IP, hostname, Mac address, OS Information etc.
Now, I have all of the above, except the OS version. Does anyone have a clue on how I could achieve this?
I'm stuck.
Thanks in advance, Christophe
You could run Nmap using Process class from System.Diagnostics and parse the result:
var process = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = "cmd.exe",
Arguments = "/c nmap -O -v targethost",
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true
}
};
process.Start();
while (!process.StandardOutput.EndOfStream)
{
string line = process.StandardOutput.ReadLine();
// here you can parse to obtain the operating system
}
Creating your own OS detector in C# would be hard but if you are interested in an overview of how it works you can find it in this Nmap chapter: Chapter 8. Remote OS Detection
Use WMI, add reference to - System.Management dll and provide namespace, use following code with appropriate parameters-
ManagementScope scope = new ManagementScope();
try
{
ConnectionOptions conOptions = new ConnectionOptions();
options.Username = "<Provide username>";
options.Password = "<Provide password>";
options.EnablePrivileges = true;
options.Authority = "ntlmdomain:<domianname>";
scope = new ManagementScope(#"\\<IP address/machine name>\root\CIMV2", options);
scope.Connect();
SelectQuery query = new SelectQuery("SELECT * FROM Win32_OperatingSystem");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
using (ManagementObjectCollection queryCollection = searcher.Get())
{
foreach (ManagementObject m in queryCollection)
{
Console.WriteLine(string.Format("Computer Name : {0}", m["csname"]));
Console.WriteLine(string.Format("Windows Directory : {0}", m["WindowsDirectory"]));
Console.WriteLine(string.Format("Operating System: {0}", m["Caption"]));
Console.WriteLine(string.Format("Version: {0}", m["Version"]);
Console.WriteLine(string.Format("Manufacturer : {0}", m["Manufacturer"]));
}
}
}
catch (Exception ex)
{
}
You must have access right to steal this info else you will get Access right exception.