I was wondering if it's possible to tell if a remote server is up or down using C#? First I have a method to shut down the server:
private static void RestartSecondServer()
{
Console.WriteLine("Computer details retrieved using Windows Management Instrumentation (WMI)");
//Connect to the remote computer
ConnectionOptions co = new ConnectionOptions();
co.Username = #"***********";
co.Password = "*********";
ManagementScope ms = new ManagementScope("\\\\******\\root\\cimv2", co);
//Query remote computer across the connection
ObjectQuery oq = new System.Management.ObjectQuery("SELECT * FROM Win32_OperatingSystem");
ManagementObjectSearcher query1 = new ManagementObjectSearcher(ms, oq);
ManagementObjectCollection queryCollection1 = query1.Get();
foreach (ManagementObject mo in queryCollection1)
{
string[] ss = {""};
mo.InvokeMethod("Reboot", ss);
Console.WriteLine(mo.ToString());
Console.WriteLine("Reboot complete");
//Process.Start("shutdown", "/r /t 0");
}
}
Now I want to create a method to see if this remote server which is in the process of being restarted is down. I tried a generic pinging method but it was returning true/success.
Can a server be successfully pinged if it's in the process of being restarted? Is it possible to tell if the server is being restarted?
Related
My requirement is to get installed software details of vm machine of azure and store the details in db. but when I try to get the details using System.Management class I am getting the below error
System.Runtime.InteropServices.COMException: 'The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)'
below is my sample code I am using to get the software details
string SoftwareQuery = "SELECT * FROM Win32_Product";
ConnectionOptions connection = new ConnectionOptions();
connection.Username = "bla bla";
connection.Password = "Password";
connection.EnablePrivileges = true;
connection.Impersonation = ImpersonationLevel.Impersonate;
ManagementScope managementScope = new ManagementScope(#"\\xxxx.xxxx.cloudapp.azure.com:3389\root\CIMV2", connection);
managementScope.Path = ManagementPath.DefaultPath;
managementScope.Connect();
ObjectQuery queryObj = new ObjectQuery(SoftwareQuery);
ManagementObjectSearcher searcher = new ManagementObjectSearcher(managementScope, queryObj);
foreach (ManagementBaseObject managementObj in searcher.Get())
{
//get the software list here
}
Note: The above code is working on intranet properly
Please let me know anyone have solution on this.
It might be related to the Windows Management Instrumentation service being in a stopped state. Take a look at Starting and Stopping the WMI Service.
Hope it helps!
I am trying to detect if screen saver is running on a remote PC using WMI. The remote PC is Windows 7, but it should work for W8/W10 as well.
So far I was testing having screen saver set manually on the remote PC (via control panel) and relying on WMI Win32_Process containing SCREEN_SAVER_NAME.SCR:
ConnectionOptions options = new ConnectionOptions();
options.Username = "Username";
options.Password = "password";
ManagementScope scope =
new ManagementScope(
"\\\\10.1.1.1\\root\\cimv2", options);
scope.Connect();
while (true)
{
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_Process");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (var item in queryCollection)
{
if ((string)item["Description"] == "PhotoScreensaver.scr")
{
Console.WriteLine("screensaver running");
}
}
}
This works fine when the screen saver is set via control panel on the remote PC.
However, when setting the screen saver via group policy, WMI Win32_Process no longer lists the .SCR file and my software obviously doesn't work as expected.
Any idea how to detect running screen savers, which was set using GPO?
I am trying to connect (locally) to get a list of virtual machines and their properties. I have hacked some code I found, but my code is failing to connect so I can only assume that the connection string is wrong.
Using Server 2012, Hyper-V
private void listVirtualMachines() {
ManagementScope manScope = new ManagementScope(#"\\LOCALHOST\root\cimv2");
if (manScope.IsConnected) {
ObjectQuery queryObj = new ObjectQuery("SELECT * FROM Msvm_ComputerSystem");
// connect and set up our search
ManagementObjectSearcher vmSearcher = new ManagementObjectSearcher(manScope, queryObj);
ManagementObjectCollection vmCollection = vmSearcher.Get();
// loop through the machines
foreach (ManagementObject vm in vmCollection) {
// display VM details
LogString(vm["ElementName"].ToString());
LogString(vm["EnabledState"].ToString());
LogString(vm["Description"].ToString());
}
} else {
//WE END UP HERE EVERY TIME!
LogString("Cannot Connect to ManagementScope!");
}
} //funct
In Server 2012, Msvm_ComputerSystem is in the WMI namespace root\virtualization\v2 so the code should be:
ManagementScope manScope = new ManagementScope(#"\\.\root\virtualization\v2");
manScope.Connect();
I'm using C# to call GetVolumeInformation on a remote machine. I can hit the remote harddrives easily as there is a default share setup of c$ or whatever. However, CD/DVD do not have a default setup. How can I read the remote CD/DVD drive using a PInvoke call or something else?
If I can't do it using C#, I could always use PowerShell or WMI.
The WMI allows you to get system information of a remote machine without problems, only you need set the remote WMI access in the machine and use a valid user and password. on this case you can use the Win32_LogicalDisk and Win32_CDROMDrive classes to retrieve the info which you need.
Try this C# sample.
using System;
using System.Collections.Generic;
using System.Management;
using System.Text;
namespace GetWMI_Info
{
class Program
{
static void Main(string[] args)
{
try
{
string ComputerName = "localhost";//set the remote machine name here
ManagementScope Scope;
if (!ComputerName.Equals("localhost", StringComparison.OrdinalIgnoreCase))
{
ConnectionOptions Conn = new ConnectionOptions();
Conn.Username = "";//user
Conn.Password = "";//password
Conn.Authority = "ntlmdomain:DOMAIN";
Scope = new ManagementScope(String.Format("\\\\{0}\\root\\CIMV2", ComputerName), Conn);
}
else
Scope = new ManagementScope(String.Format("\\\\{0}\\root\\CIMV2", ComputerName), null);
Scope.Connect();
ObjectQuery Query = new ObjectQuery("SELECT * FROM Win32_CDROMDrive");
ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, Query);
foreach (ManagementObject WmiObject in Searcher.Get())
{
Console.WriteLine("{0,-35} {1,-40}","DeviceID",WmiObject["DeviceID"]);// String
Console.WriteLine("{0,-35} {1,-40}","Drive",WmiObject["Drive"]);// String
}
}
catch (Exception e)
{
Console.WriteLine(String.Format("Exception {0} Trace {1}",e.Message,e.StackTrace));
}
Console.WriteLine("Press Enter to exit");
Console.Read();
}
}
}
Using Powershell and WMI.
Try this:
Get-WmiObject -computername MyremotePC Win32_CDROMDrive | Format-List *
You need administrative credential on remote computer.
You can P/invoke in powershell the GetVolumeInfomation adding it as type using Add-Type (Some example here).
If you're trying to read data on the disk of a remote CD/DVD that isn't shared I don't know any way to do it.
I am trying to shutdown and start the sql server on a remote computer (on the same network), i have used this code
ConnectionOptions options = new ConnectionOptions();
options.Username = userName;
options.Password = password;
ManagementScope scope =
new ManagementScope(
string.Format(#"\\{0}\root\cimv2", serverFullName),
options);
scope.Connect();
ObjectQuery query = new ObjectQuery(
string.Format(#"SELECT * FROM Win32_Process WHERE Name='{0}'",
processToTerminate));
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
{
m.InvokeMethod("Terminate", null);
}
is there another way of doing that ?
how can i start the process (if Terminate close it)?
Thank you
What about using the ServiceController class? (see MSDN)
// just replace the params with your values
ServiceController sc = new ServiceController("SERVICENAME", "MACHINENAME");
if (sc.Status.Equals(ServiceControllerStatus.Running))
sc.Stop();
This should do the trick.
hth
It would seem a lot easier to just use the ServiceController class, that you can give a service name and computer name to, and then call methods such as Start and Stop.
Killing a process and stoping a service are two different things. A service could spawn other processes that will remain lingering. Also, you are effectively pulling the plug on the process. It isn't being given any time to stop gracefully, write everything to disk, etc.
Instead you should use the Win32_Service WMI object to find your service. This has a StartService and StopService method, which will allow you to stop and start it as you need.
Mind you, this WMI object is about services, not processes, so you will have to tweak your code to stop it by the service name, not the process name. Something like this:
ConnectionOptions options = new ConnectionOptions();
options.Username = userName;
options.Password = password;
ManagementScope scope = new ManagementScope(string.Format(#"\\{0}\root\cimv2", serverFullName), options);
scope.Connect();
ObjectQuery query = new ObjectQuery(string.Format(#"SELECT * FROM Win32_Service WHERE Name='{0}'",serviceToStop));
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
{
m.InvokeMethod("StopService", null);
}
Then later on you can use InvokeMethod on StartService.
you can do some like this to start and stop your sql server
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.FileName = "net start \"Sql Server (SQLEXPRESS)\"";
process.Start();