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
Related
I am an administrator and want to delegate helpdesk stuff to do some applications silent installs which requires admin. rights, I tried below code and always gets error message 'RPC server is unavailable', I cannot figure out what's wrong with my code, any help will be highly appreciated.
public static string ahmed(string machine, string username, string password, string domain)
{
try
{
ConnectionOptions connectionOptions = new ConnectionOptions();
connectionOptions.Authority = "ntlmdomain:" + domain + #"\" + machine;
connectionOptions.Username = username;
connectionOptions.Password = password;
connectionOptions.Impersonation = ImpersonationLevel.Delegate;
connectionOptions.Authentication = AuthenticationLevel.PacketPrivacy;
//define the WMI root name space
ManagementScope scope = new ManagementScope(#"\\" + machine + "." + domain + #"\root\CIMV2", connectionOptions);
//define path for the WMI class
ManagementPath p = new ManagementPath("Win32_Process");
//define new instance
ManagementClass processClass = new ManagementClass(scope, p, null);
// Create an array containing all
// arguments for the method
object[] methodArgs =
{#"mkdir c:\testtest", null, null, 0};
//Execute the method
object result =
processClass.InvokeMethod(
"Create", methodArgs);
return "done";
}
catch (ManagementException me)
{
return me.Message;
}
catch (COMException ioe)
{
return ioe.Message;
}
}
Remote shutdown command not working for Windows Embedded computer. It is working fine for normal windows computers. Is there something special that we need to do for windows embedded?
I am trying to send following command from my C# program. Also tried over commandline.
shutdown /s /f /m \\192.168.100.2 /t 5 /d u:0:0 /c "The Computer is shutting down"
Code looks like following
Process proc = new Process();
proc.EnableRaisingEvents = false;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.FileName = "shutdown.exe";
proc.StartInfo.UserName = adminName;
proc.StartInfo.Password = adminPassword;
proc.StartInfo.Domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName;
proc.StartInfo.Arguments = string.Format(#" /s /f /m \\{0} /t 5 /d u:0:0 /c ""The computer is shutting down"" ", ipAddress);
try
{
proc.Start();
}
catch( Exception ex )
{
// log
}
Command line tools didn't work and I ended up writing following code to shutdown computer remotely. However the code will work also for the local computer.
public void ShutdownRemotePC(string ipAddress, string adminName, string adminPassword)
{
try
{
var query = new SelectQuery("Win32_OperatingSystem");
// create always a new management scope
// create a default one and get immediate info if connection is be possible
ConnectionOptions connectionOptions = new ConnectionOptions
{
Impersonation = ImpersonationLevel.Impersonate,
EnablePrivileges = true,
//changed to packet privacy as some service requires it
Authentication = AuthenticationLevel.PacketPrivacy,
Username = ipAddress + #"\" + adminName,
Password = adminPassword,
Timeout = TimeSpan.FromMilliseconds(5000)
};
string name = #"\\" + ipAddress + #"\root\cimv2";
ManagementScope managementScope = new ManagementScope(name, connectionOptions);
// if already connected is checked inside connect
managementScope.Connect();
if( !managementScope.IsConnected )
{
//Shutdown Failed. Managment Scope could not be connected.
return;
}
using( var searcher = new ManagementObjectSearcher(managementScope, query) )
{
// impersonate the searcher if not allready done
searcher.Scope.Options.Impersonation = System.Management.ImpersonationLevel.Impersonate;
searcher.Scope.Options.EnablePrivileges = true;
using( ManagementObjectCollection found = searcher.Get() )
{
foreach( ManagementObject os in found )
{
// Obtain in-parameters for the method
using( ManagementBaseObject inParams = os.GetMethodParameters("Win32Shutdown") )
{
// Add the input parameters.
inParams["Flags"] = 12;
// Execute the method and obtain the return values.
using( ManagementBaseObject outParams = os.InvokeMethod("Win32Shutdown", inParams, null) )
{
if( outParams != null )
{
var result = Convert.ToInt32(outParams["returnValue"]);
if( result == 0 )
{
Logger.LogError("Shutdown successfully.");
}
}
}
}
}
}
}
}
catch( Exception ex )
{
// Shutdown PC=failed.
}
}
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'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.
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.