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?
Related
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?
I tried to connect to a remote PC and query for its processes but when I run the code, it got connected with my local PC and obtained its processes instead of the remote PC.
The code is
ManagementScope scope = new ManagementScope(#"\\remote-user\\root\\cimv2");
scope.Connect();
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_Process");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
You appear to be passing a username ("remote-user") instead of a hostname of the remote machine to your management scope. Change your code to e.g.:
ConnectionOptions options = new ConnectionOptions();
options.Password = "remoteUserPassword"; // you may want to avoid plain text password and use SecurePassword property instead
options.Username = "remote-user";
ManagementScope scope = new ManagementScope(#"\\remoteMachineHostname\root\cimv2", options);
(I assume that remote-user is Full computer name) change:
ManagementScope scope = new ManagementScope(#"\\remote-user\\root\\cimv2");
to:
ManagementScope scope = new ManagementScope(#"\\<FullComputerName>\root\cimv2");
another option:
ManagementScope scope = new ManagementScope("\\\\<FullComputerName>\\root\\cimv2");
See this link (it's Microsoft example)
Edit
if you want to connect with deffrent user you need to pass ConnectionOptions (see above link)
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();
How am I able do find all local printers of the machine where the program is running with a user that doesn't have admin rights. I need to remap the printer IP and set the printer as default. My idea is to use impersonation to do this but I don't know where to find the printer and if it is a good solution to use impersonation.
Thanks for any help!
I don't think you will have any luck with this. Impersonation will not work here and just throw a exception. You can try this by making a impersonation and try to open Environment.Domain it should give you a exception.
You can try something like this without impersonation:
ManagementScope mscope = new ManagementScope(#"\root\CIMV2", options);
mscope.Connect();
System.Management.ObjectQuery oQuery = new ObjectQuery("Select * from Win32_TCPIPPrinterPort");
System.Management.ManagementObjectSearcher searcher = new ManagementObjectSearcher(mscope, oQuery);
ManagementObjectCollection moCollection = searcher.Get();
foreach (ManagementObject mo in moCollection)
{
string name = mo["Name"].ToString();
if (name.Equals(this.portName))
{
System.Threading.Thread.Sleep(10000);
mo["HostAddress"] = this.printerIP;
mo.Put();
Console.WriteLine("Adjusted Printer Port to new IP address " + this.printerIP);
return true;
}
}
I need to check a group of servers to see whether the anti virus is up-to-date and running. Tricky thing is that they are spread over Windows 2003 and 2008 servers and I need to be able to check them all.
Is there any way of doing this with C# or VB.NET?
I have briefly looked around using WMI, but it appears on 2008/win7 computers Microsoft has changed what information they give back to you.
In summary, I need the following:
AV name
AV version
AV Up-to-Date
AV Enabled/Running
Can anyone help?
Sample can be found here using WMI as you mentioned. The poster states this is being done on a Win 7 machine; so the code below should get you started...
ConnectionOptions _connectionOptions = new ConnectionOptions();
//Not required while checking it in local machine.
//For remote machines you need to provide the credentials
//options.Username = "";
//options.Password = "";
_connectionOptions.EnablePrivileges = true;
_connectionOptions.Impersonation = ImpersonationLevel.Impersonate;
//Connecting to SecurityCenter2 node for querying security details
ManagementScope _managementScope = new ManagementScope(string.Format("\\\\{0}\\root\\SecurityCenter2", ipAddress), _connectionOptions);
_managementScope.Connect();
//Querying
ObjectQuery _objectQuery = new ObjectQuery("SELECT * FROM AntivirusProduct");
ManagementObjectSearcher _managementObjectSearcher =
new ManagementObjectSearcher(_managementScope, _objectQuery);
ManagementObjectCollection _managementObjectCollection = _managementObjectSearcher.Get();
if (_managementObjectCollection.Count > 0)
{
foreach (ManagementObject item in _managementObjectCollection)
{
Console.WriteLine(item["displayName"]);
//For Kaspersky AntiVirus, I am getting a null reference here.
//Console.WriteLine(item["productUptoDate"]);
//If the value of ProductState is 266240 or 262144, its an updated one.
Console.WriteLine(item["productState"]);
}
}
Depending on how your environment is setup you may need to specify your security and permissions. You should also note that some antivirus products (like McAfee) do not make data available through WMI.
You can query the Antivirus information from WMI using this snippet:
string computer = Environment.MachineName;
string wmipath = #"\\" + computer + #"\root\SecurityCenter";
string query = #"SELECT * FROM AntivirusProduct";
ManagementObjectSearcher searcher = new ManagementObjectSearcher(wmipath, query);
ManagementObjectCollection results = searcher.Get();
foreach (ManagementObject result in results)
{
// do something with `result[value]`);
}