using WMI to uninstall applications remotely - c#

I am trying to write a mini w32 executable to remotely uninstall an application using WMI.
I can list all the installed applications using this code below but i couldnt find a way to uninstall the application remotely thru WMI and C#
I know I can do same using msiexec as a process but I wish to solve this using WMI if its possible...
Thanks,
Cem
static void RemoteUninstall(string appname)
{
ConnectionOptions options = new ConnectionOptions();
options.Username = "administrator";
options.Password = "xxx";
ManagementScope scope = new ManagementScope("\\\\192.168.10.111\\root\\cimv2", options);
scope.Connect();
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_Product");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
{
// Display the remote computer information
Console.WriteLine("Name : {0}", m["Name"]);
if (m["Name"] == appname)
{
Console.WriteLine(appname + " found and will be uninstalled... but how");
//need to uninstall this app...
}
}
}

Have a look at WMI Code Creator (a free tool from Microsoft) — it can generate WMI code for you in various languages, including C#.
Here's an example illustrating the Win32_Product.Uninstall method usage. You need to know the GUID, name and version of the application you want to uninstall, as they are the key properties of the Win32_Product class:
...
ManagementObject app =
new ManagementObject(scope,
"Win32_Product.IdentifyingNumber='{99052DB7-9592-4522-A558-5417BBAD48EE}',Name='Microsoft ActiveSync',Version='4.5.5096.0'",
null);
ManagementBaseObject outParams = app.InvokeMethod("Uninstall", null);
Console.WriteLine("The Uninstall method result: {0}", outParams["ReturnValue"]);
If you have partial info about the application (e.g. only name or name and version), you can use a SELECT query to obtain the corresponding Win32_Process object:
...
SelectQuery query = new SelectQuery("Win32_Product", "Name='Microsoft ActiveSync'");
EnumerationOptions enumOptions = new EnumerationOptions();
enumOptions.ReturnImmediately = true;
enumOptions.Rewindable = false;
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query, options);
foreach (ManagementObject app in searcher.Get())
{
ManagementBaseObject outParams = app.InvokeMethod("Uninstall", null);
Console.WriteLine("The Uninstall method result: {0}", outParams["ReturnValue"]);
}

Related

c# connect to remote using wmi needs /etc/hosts

I am using below code to connect remote computer however it needs that the remote computer must be exist at '#drivers/etc/hosts' file.
If i don't write the information about remote computer on /etc/hosts file it gives below error;
the rpc server is unavailable
How can i connect to rdp without modifying '#drivers/etc/hosts' file ?
public void GetSystemInformation()
{
ConnectionOptions options = new ConnectionOptions();
options.Username = "test";
options.Password = "test";
options.EnablePrivileges = true;
ManagementScope scope = new ManagementScope("\\\\someip\\root\\cimv2", options);
scope.Connect();
//Query system for Operating System information
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_OperatingSystem");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
{
// Display the remote computer information
Console.WriteLine("Computer Name : {0}",m["csname"]);
Console.WriteLine("Windows Directory : {0}", m["WindowsDirectory"]);
Console.WriteLine("Operating System: {0}", m["Caption"]);
Console.WriteLine("Version: {0}", m["Version"]);
Console.WriteLine("Manufacturer : {0}",m["Manufacturer"]);
}
}

Application Pool Start/Stop/Recycle "This method is not implemented in any class" Error

I am having issues starting/stopping/recycling my application pool that is located on a remote server. I have coded a function that will tell me what application pools are on a server (along with their status). However, I get the error "System.Management.ManagementException: This method is not implemented in any class" whenever I run the following snippet of code.
// getScope creates a ManagementScope object
ManagementScope scope = getScope(serverName, "microsoftiisv2", username, password);
scope.Connect();
ObjectQuery objectquery = new ObjectQuery("SELECT * FROM IISApplicationPoolSetting");
ManagementObjectSearcher mos = new ManagementObjectSearcher(scope, objectquery);
ManagementObjectCollection moc = mos.Get();
foreach (ManagementObject mo in moc)
{
string path = mo["Name"].ToString();
string name = path.Split('/')[2];
string pstate = mo["AppPoolState"].ToString();
if (name == applicationPoolName && pstate == "2")
{
string[] parameters = { "" };
mo.InvokeMethod("Stop", null);
// I have also tried the following alternatives:
// mo.InvokeMethod( "Stop", parameters )
}
}
I have tried looking at the Windows documentation, but have had no success understanding why my code does not work.

Is a process running on a remote machine?

I have three remote PC's to which I remotely connect. I am trying to write a simple Windows application that would display in a single window whether a particular process is running on either of the machines, e.g.
Server1: Chrome not running
Server2: Chrome IS running
Server3: Chrome IS running
I used WMI and C#. So far I've got this much:
ConnectionOptions connectoptions = new ConnectionOptions();
connectoptions.Username = #"domain\username";
connectoptions.Password = "password";
//IP Address of the remote machine
string ipAddress = "192.168.0.217";
ManagementScope scope = new ManagementScope(#"\\" + ipAddress + #"\root\cimv2");
scope.Options = connectoptions;
//Define the WMI query to be executed on the remote machine
SelectQuery query = new SelectQuery("select * from Win32_Process");
using (ManagementObjectSearcher searcher = new
ManagementObjectSearcher(scope, query))
{
ManagementObjectCollection collection = searcher.Get();
foreach (ManagementObject process in collection)
{
// dwarfs stole the code!! :'(
}
}
I think it is all set up correctly, but if I MessageBox.Show(process.ToString()) inside the foreach loop, I get a whole bunch of message boxes with the following text:
\\username\root\cimv2:W32_Process.Handle="XXX"
I am kind of stuck. Is there any way I can "translate" that XXX to a process name? Or else, how can actually get the names of the processes so I can use an if statement to check whether it is a "chrome" process?
Or...is my implementation an overkill? Is there an easier way to accomplish this?
Thanks a lot!
In your foreach, try this:
Console.WriteLine(process["Name"]);
You can filter the name of the process to watch in the WQL sentence, so you can write something like this
SelectQuery query = new SelectQuery("select * from Win32_Process Where Name='Chrome.exe'");
Try this sample app
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";
ManagementScope Scope;
if (!ComputerName.Equals("localhost", StringComparison.OrdinalIgnoreCase))
{
ConnectionOptions Conn = new ConnectionOptions();
Conn.Username = "";
Conn.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_Process Where Name='Chrome.exe'");
ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, Query);
foreach (ManagementObject WmiObject in Searcher.Get())
{
//for each instance found, do something
Console.WriteLine("{0,-35} {1,-40}","Name",WmiObject["Name"]);
}
}
catch (Exception e)
{
Console.WriteLine(String.Format("Exception {0} Trace {1}",e.Message,e.StackTrace));
}
Console.WriteLine("Press Enter to exit");
Console.Read();
}
}
}
Try Process.GetProcesses("chrome", "computerName");
Defined in System.Diagnostics.Process as
public static Process[] GetProcessesByName(
string processName,
string machineName)

terminating process requires WQL "SELECT *..."?

i'm writing code to terminate specific processes after a specified amount of time. i'm using the below code (simplified for post):
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Name, CreationDate FROM Win32_Process WHERE Name = 'foo'");
foreach (ManagementObject process in searcher.Get())
{
process.InvokeMethod("Terminate", null);
}
the problem -- using a WQL statement of SELECT Name, CreationDate throws an exception when trying to do the terminate:
"Operation is not valid due to the current state of the object."
...but, using SELECT * works and terminates the process. why is this -- is there a specific WMI column that's needed in the resultset?
thanks!
When you executes a WMI method, the WMI internally searh for the WMI Object path to identify the instance over the method will be executed.
In this case for the Win32_Process WMI class the WMI Object Path looks like Win32_Process.Handle="8112", So as you see the Handle property is part of the WMi Object path and must be included in your WQL sentece,
Check this sample.
using System;
using System.Collections.Generic;
using System.Management;
using System.Text;
//this will all the notepad running instances
namespace GetWMI_Info
{
class Program
{
static void Main(string[] args)
{
try
{
string ComputerName = "localhost";
ManagementScope Scope;
if (!ComputerName.Equals("localhost", StringComparison.OrdinalIgnoreCase))
{
ConnectionOptions Conn = new ConnectionOptions();
Conn.Username = "";
Conn.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 Handle FROM Win32_Process Where Name='notepad.exe'");
ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, Query);
foreach (ManagementObject WmiObject in Searcher.Get())
{
WmiObject.InvokeMethod("Terminate", null);
}
}
catch (Exception e)
{
Console.WriteLine(String.Format("Exception {0} Trace {1}",e.Message,e.StackTrace));
}
Console.WriteLine("Press Enter to exit");
Console.Read();
}
}
}

Kill a process on a remote machine in C#

This only helps kills processes on the local machine. How do I kill processes on remote machines?
You can use wmi. Or, if you don't mind using external executable, use pskill
I like this (similar to answer from Mubashar):
ManagementScope managementScope = new ManagementScope("\\\\servername\\root\\cimv2");
managementScope.Connect();
ObjectQuery objectQuery = new ObjectQuery("SELECT * FROM Win32_Process Where Name = 'processname'");
ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(managementScope, objectQuery);
ManagementObjectCollection managementObjectCollection = managementObjectSearcher.Get();
foreach (ManagementObject managementObject in managementObjectCollection)
{
managementObject.InvokeMethod("Terminate", null);
}
I use the following code. psKill is also a good way to go but sometimes you need to check the some other stuff, for example in my case remote machine was running multiple instances of same process but with different command line arguments, so following code worked for me.
ConnectionOptions connectoptions = new ConnectionOptions();
connectoptions.Username = string.Format(#"carpark\{0}", "domainOrWorkspace\RemoteUsername");
connectoptions.Password = "remoteComputersPasssword";
ManagementScope scope = new ManagementScope(#"\\" + ipAddress + #"\root\cimv2");
scope.Options = connectoptions;
SelectQuery query = new SelectQuery("select * from Win32_Process where name = 'MYPROCESS.EXE'");
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
{
ManagementObjectCollection collection = searcher.Get();
if (collection.Count > 0)
{
foreach (ManagementObject mo in collection)
{
uint processId = (uint)mo["ProcessId"];
string commandLine = (string) mo["CommandLine"];
string expectedCommandLine = string.Format("MYPROCESS.EXE {0} {1}", deviceId, deviceType);
if (commandLine != null && commandLine.ToUpper() == expectedCommandLine.ToUpper())
{
mo.InvokeMethod("Terminate", null);
break;
}
}
}
}

Categories