Start exe file on remote machine - c#

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.

Related

shutdown a specific computer in a network by using C# [duplicate]

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

Delete file on Remote Server Using WMI

I'm trying to delete an existing file on the remote server using WMI.
Here's my code:
string name = #"\\servername\\OCROut\\basketball.txt";
ConnectionOptions options = new ConnectionOptions(remoteServer, "username", "password", "ntlmdomain:domainName", ImpersonationLevel.Impersonate, AuthenticationLevel.Default, true, null, System.TimeSpan.MaxValue);
ManagementScope scope = new ManagementScope("\\\\server\\root\\cimv2", options);
scope.Connect();
var query = new ObjectQuery(string.Format("SELECT * FROM CIM_Datafile WHERE Drive = 'D' AND Name = '{0}' AND Filename = 'basketball' and Extension = 'txt'", name));
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
var tobeDeleted = searcher.Get();
foreach (ManagementObject item in searcher.Get())
{
item.InvokeMethod("Delete", null);
}
The Query is working file but but my Count = 0 when i'm executing the searcher.Get() method. I tried everything, different slashes, without the drive, Filename and extension but nothing seem to be working and i know that the file exists.
Any help would be highly appreciated.
It seems which you are passing wrong values in the params. the Name property must contain the full local path of the file, so try this :
string name = #"D:\\OCROut\\basketball.txt";
var query = new ObjectQuery(string.Format("SELECT * FROM CIM_Datafile WHERE Name = '{0}'", name));
WMI Script to delete single/multi files in remote server
#for single file
$file = Get-WmiObject -Query "Select * from CIM_Datafile Where Name='c:\\Desktop\\a.txt'" -ComputerName 10.14.34.81 -Credential administrator
if($file)
{
$file.delete()|out-null
}
#For Multiple files in a directory
$files = Get-WmiObject -Query "ASSOCIATORS OF {Win32_Directory.Name='c:\Desktop\Temp'} Where ResultClass = CIM_DataFile" -ComputerName 10.14.34.81 -Credential administrator
if($files)
{
$files|%{$_.Delete()|out-null}
}

WMI throwing Exception "Invalid Query" on second attempt to query the same server

I have a following code, almost all the time this code works for most of my server, but for some specific servers, it just fails on second part of query. this code query the SQL Server Service First and in second part it queries the SQL Sevrer Agent Service.
I have tried all possible combination of creating another Scope and Query Object, but somehow the server I am trying to query does not return seccond part, looks like after the scope is connected and first query is executed, second part is blocked by something on server..! Any help on this one is appreciated.. almost 99% of servers works fine and returns desire results, but just 2 or 3 servers fails for second part..
If this is WMI issue on the server it self..? is there any other way to achieve these status..? like IPC or Sockets..? please help..!
Hash.
try
{
agentserviceName = "SQLSERVERAGENT";
serviceName = "MSSQLSERVER";
query = new System.Management.SelectQuery(string.Format("select name, startname, State, StartMode from Win32_Service where name = '{0}'", serviceName));
ManagementScope scope = new ManagementScope("\\\\" + srvName + "\\root\\cimv2");
//ManagementScope scope = new ManagementScope("\\\\ST0176V\\root\\cimv2");
scope.Connect();
System.Management.ManagementObjectSearcher searcher = new System.Management.ManagementObjectSearcher(scope, query);
// MessageBox.Show((String)dgv_ChangeSvcAccount.Rows[i].Cells[1].Value.ToString());
foreach (ManagementObject service in searcher.Get())
{
dgv_ChangeSvcAccount.Rows[i].Cells[4].Value = service["startname"];
dgv_ChangeSvcAccount.Rows[i].Cells[4].Tag = serviceName;
dgv_ChangeSvcAccount.Rows[i].Cells[5].Value = "Currently : " + service["State"] + " - Set As : " + service["StartMode"];
}
if (searcher.Get().Count == 0)
{
dgv_ChangeSvcAccount.Rows[i].Cells[4].Value = "NO SQL Service Found";
}
searcher.Dispose();
ManagementScope scope2 = new ManagementScope("\\\\" + srvName + "\\root\\cimv2");
// ObjectQuery query2 = new ObjectQuery("SELECT * FROM Win32_Service WHERE NAME LIKE '" + serviceName.ToString().ToUpper() + "'");
System.Management.SelectQuery query2 = new System.Management.SelectQuery(string.Format("select name, startname, State, StartMode from Win32_Service where name like '{0}'", agentserviceName));
System.Management.ManagementObjectSearcher searcher1 = new System.Management.ManagementObjectSearcher(scope2, query2);
foreach (ManagementObject service in searcher1.Get()) // <---- this line throws exception for invalid query, and it is always 2 servers which does that, rest of servers returns proper results. the servers which throws this Invlid Query exceptions are Windows 2000 Server with SP4.
{
dgv_ChangeSvcAccount.Rows[i].Cells[6].Value = service["startname"];
dgv_ChangeSvcAccount.Rows[i].Cells[6].Tag = agentserviceName;
dgv_ChangeSvcAccount.Rows[i].Cells[7].Value = "Currently : " + service["State"] + " - Set As : " + service["StartMode"];
}
searcher1.Dispose();
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
Since, as we've been discussing in the comments, we're thinking it might have to do with having multiple active ManagementScope objects, try changing the first half of your code to this:
string agentserviceName = "SQLSERVERAGENT";
string serviceName = "MSSQLSERVER";
// Let the SelectQuery class build our WQL query text...
string className = "Win32_Service";
string condition = string.Format("Name = '{0}'", serviceName);
string[] selectedProperties = new string[] { "Name", "StartName", "State", "StartMode" };
SelectQuery query = new SelectQuery(className, condition, selectedProperties);
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
{
searcher.Scope = new ManagementScope("\\\\" + srvName + "\\root\\cimv2");
foreach (ManagementObject service in searcher.Get())
{
dgv_ChangeSvcAccount.Rows[i].Cells[4].Value = service["startname"];
dgv_ChangeSvcAccount.Rows[i].Cells[4].Tag = serviceName;
dgv_ChangeSvcAccount.Rows[i].Cells[5].Value = "Currently : " + service["State"] + " - Set As : " + service["StartMode"];
}
if (searcher.Get().Count == 0)
{
dgv_ChangeSvcAccount.Rows[i].Cells[4].Value = "NO SQL Service Found";
}
}
// Second query goes here...
That will dispose the ManagementObjectSearcher for the first query when it's done being used, and also ensure that it holds the only reference to the ManagementScope for the remote server.

OS Information of networkclient using C#

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.

What Windows Class to use when I want to start a process remotely

I want to use c# and WMI to start a process remotely in another computer. I've made some initial research and found out that i ultimately have to use a processclass. The "Win32_Process" was the first thing that seemed obvious to be used, however, it seems it is limited to represent only local processes. What other Windows process classes can I use?
Here is what the code when using Win32_ScheduledJob class:
static public String RemoteConnect()
{
try
{
ConnectionOptions conn = new ConnectionOptions();
conn.Username = #"JV";
conn.Password = #"Nazpal6180";
conn.EnablePrivileges = true;
conn.Impersonation = System.Management.ImpersonationLevel.Impersonate;
ManagementScope scope = new ManagementScope("\\\\phsd194-JV\\root\\cimv2", conn);
//scope.Options.Impersonation = System.Management.ImpersonationLevel.Impersonate;
//scope.Options.EnablePrivileges = true;
scope.Connect();
ManagementPath managementPath = new ManagementPath("Win32_ScheduledJob");
ObjectGetOptions objectGetOptions = new ObjectGetOptions();
ManagementClass classInstance = new ManagementClass(scope, managementPath, objectGetOptions);
object[] objectsIn = new object[7];
objectsIn[0] = "calc.exe";
objectsIn[1] = "********140000.000000+480";
objectsIn[5] = true;
object outParams = classInstance.InvokeMethod("Create", objectsIn);
String response = "Creation of the process returned: " + outParams;
return response;
}
catch (ManagementException err)
{
String response = "An error occurred while trying to execute the WMI method: " + err.Message;
//Console.WriteLine("An error occurred while trying to execute the WMI method: " + err.Message);
return response;
}
}
As you point in your comments, the Win32_Process.Create method cannot be used to start an interactive process remotely, so as workaround you can use the Win32_ScheduledJob class with the Create method.
Check this sample app, which start the notepad in a remote machine in one minute , (Assuming which the time of the remote machine is the same of the local machine, if not you can get the local time using Win32_LocalTime or Win32_UtcTime from the remote machine and then convert to UTC).
using System;
using System.Collections.Generic;
using System.Text;
using System.Management;
namespace ConsoleApplication11
{
class Program
{
private static string DateTimetoUTC(DateTime dateParam)
{
string buffer = dateParam.ToString("********HHmmss.ffffff");
TimeSpan tickOffset = TimeZone.CurrentTimeZone.GetUtcOffset(dateParam);
buffer += (tickOffset.Ticks >= 0) ? '+' : '-';
buffer += (Math.Abs(tickOffset.Ticks) / System.TimeSpan.TicksPerMinute).ToString("d3");
return buffer;
}
static void Main(string[] args)
{
try
{
ConnectionOptions conn = new ConnectionOptions();
conn.Username = "theusername";
conn.Password = "password";
//connectoptions.Authority = "ntlmdomain:";
conn.EnablePrivileges = true;
ManagementScope scope = new ManagementScope(#"\\192.168.52.128\root\cimv2", conn);
scope.Connect();
Console.WriteLine("Connected");
ObjectGetOptions objectGetOptions = new ObjectGetOptions();
ManagementPath managementPath = new ManagementPath("Win32_ScheduledJob");
ManagementClass classInstance = new ManagementClass(scope, managementPath, objectGetOptions);
ManagementBaseObject inParams = classInstance.GetMethodParameters("Create");
inParams["Command"] = #"notepad.exe";
//the itme must be in UTC format
string StartTime = DateTimetoUTC(DateTime.Now.AddMinutes(1));
Console.WriteLine(StartTime);
inParams["StartTime"] = StartTime;
ManagementBaseObject outParams = classInstance.InvokeMethod("Create", inParams, null);
Console.WriteLine("JobId: " + outParams["JobId"]);
Console.ReadKey();
}
catch(ManagementException err)
{
Console.WriteLine("An error occurred while trying to execute the WMI method: " + err.Message);
Console.ReadKey();
}
}
}
}
I believe C# has just a Process class. I've used it for starting remote processes before.
I'd go for a server/client architecture where the server can start processes based on some kind of network call.

Categories

Resources