Getting Installed softwares from remote host using wmi - c#

I want to retrieve Softwares installed from remote host. I want to get details from the registry and not from Win32_Product.I am using wmi. I have tried so many examples from the net. Most of them are in vb.net i need in C#. can any one post the code..
This is the code i am using
string regKeyToGet=#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\";
string keyToRead= "DisplayName";
ConnectionOptions oConn = new ConnectionOptions();
oConn.Username = "Ravinilson";
oConn.Password = "ravi";
ManagementScope scope = new ManagementScope(#"//" + RemotePC + #"/root/default", oConn);
ManagementClass registry = new ManagementClass(scope, new ManagementPath("StdRegProv"), null);
// Returns a specific value for a specified key
ManagementBaseObject inParams = registry.GetMethodParameters("GetStringValue");
nParams["sSubKeyName"] = regKeyToGet;
inParams["sValueName"] = keyToRead;
ManagementBaseObject outParams = registry.InvokeMethod("GetStringValue", inParams, null);
return outParams["sValue"].ToString();
but it is giving "Object reference not set to an instance of an object" error.
I am getting installed applications from "Win32_Product".But it is returning only windows products.That's why i want to get data from the registry "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\".

I solved this problem by using the below script.
#PRAGMA AUTORECOVER
[dynamic, provider("RegProv"),
ProviderClsid("{fe9af5c0-d3b6-11ce-a5b6-00aa00680c3f}"),
ClassContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows
\\CurrentVersion\\Uninstall")]
class InstalledSoftware
{
[key] string KeyName;
[read, propertycontext("DisplayName")] string DisplayName;
[read, propertycontext("DisplayVersion")] string DisplayVersion;
[read, propertycontext("InstallDate")] string InstallDate;
[read, propertycontext("Publisher")] string Publisher;
};
Save above script as ".mof" file. After that you need to compile this script by using the commandprompt command "mofcomp filename.mof" . for this u need to have admin privileges. after compiling the file the above class "InstalledSoftware" will get added to the wmi classes in default root.
now u will be able to access installed applications in that pc using the class name "InstalledSoftware" through wmi. One tricky thing is that we need to compile the above script in all the remote machines from which u need to access installed softwares.

Related

Can't access hardware info of remote computer with WMI: Access is denied

I am trying to create an application that uses WMI to retrieve information about a computer on my local network. When I run it, I get an access denied error. Here is the code:
private void GetHDDdetails()
{
ConnectionOptions options = new ConnectionOptions();
options.Username = "username";
options.Password = "password";
options.Impersonation = ImpersonationLevel.Impersonate;
ManagementScope oMs = new ManagementScope("\\\\remoteHostName\\root\\cimv2", options);
ObjectQuery oQuery = new ObjectQuery("SELECT Size FROM Win32_DiskDrive");
ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(oMs, oQuery);
ManagementObjectCollection oCollection = oSearcher.Get();
foreach (ManagementObject obj in oCollection)
{
hddBox.Text = obj["Size"].ToString();
}
}
I have replaced some of the info above, such as user name and password, with placeholders for this post.
Some of the things I have tried is this: Disabling firewall on both machines, making sure TCP NetBIOS service and RCP and WMI services are running on both. The account I am using is an administrator on the local computer. Everything I have found online tells me to check these, but it is obviously something else.
If someone can point me in the right direction, that would be great.
Please check using wbemtest that you can access the information from remote machine. And i hope you are replacing remoteHostName properly.
And make changes to authentication level, if you can.
scope.Options.EnablePrivileges = true;
scope.Options.Authentication = AuthenticationLevel.PacketPrivacy;

Execute a process in a remote machine using WMI

I want to open process pon remote machine, this remote machine is inside local network.
I try this command and in the remote machine nothing happen, this user that i connect with have administrators rights.
Both machines running Windows 7
static void Main(string[] args)
{
try
{
//Assign the name of the process you want to kill on the remote machine
string processName = "notepad.exe";
//Assign the user name and password of the account to ConnectionOptions object
//which have administrative privilege on the remote machine.
ConnectionOptions connectoptions = new ConnectionOptions();
connectoptions.Username = #"MyDomain\MyUser";
connectoptions.Password = "12345678";
//IP Address of the remote machine
string ipAddress = "192.168.0.100";
ManagementScope scope = new ManagementScope(#"\\" + ipAddress + #"\root\cimv2", connectoptions);
//Define the WMI query to be executed on the remote machine
SelectQuery query = new SelectQuery("select * from Win32_process where name = '" + processName + "'");
object[] methodArgs = { "notepad.exe", null, null, 0 };
using (ManagementObjectSearcher searcher = new
ManagementObjectSearcher(scope, query))
{
foreach (ManagementObject process in searcher.Get())
{
//process.InvokeMethod("Terminate", null);
process.InvokeMethod("Create", methodArgs);
}
}
Console.ReadLine();
}
catch (Exception ex)
{
//Log exception in exception log.
//Logger.WriteEntry(ex.StackTrace);
Console.WriteLine(ex.StackTrace);
}
}
you are not opening a process with that code but you are enumerating all the running process named "iexplore.exe" and close them.
I think an easier, better way is to use SysInternals PsExec or the Task Scheduler API
If you want to use WMI your code should look like this:
object theProcessToRun = { "YourFileHere" };
ManagementClass theClass = new ManagementClass(#"\\server\root\cimv2:Win32_Process");
theClass.InvokeMethod("Create", theProcessToRun);
----------In reply to your comment------------------
First of all you need to change your attitude and approach to coding and read the code that your are copy/pasting.
Then you should study a little more about programming languages.
No I will not write the code for you. I gave you an hint to point to the right direction. now it is your turn to develop it. Have fun!!
This is script that i did for my company before this using vbs script. can search the net to convert it to C# or etc. Fundamental of the steps and how to start a service using WMI. Have a nice coding and have fun.
sUser = "TESTDomain\T-CL-S"
sPass = "Temp1234"
Set ServiceSet = GetObject("winmgmts:").ExecQuery("Select * from Win32_Service where Name = 'netlogon'")
For Each Service In ServiceSet
Service.StopService
Service.Change "netlogon",Service.PathName, , ,"Automatic",false,sUser,sPass
Service.StartService
Next
Set Service = Nothing
Set ServiceSet = Nothing

How do i reset IIS remotely using C#.Net code?

I have the IIS service running on Windows Server 2008 and i want to reset it from my windows 7 machine .
How do i reset IIS remotely using C#.Net code?
I tried using Microsoft.Web.Administration, but it doesn't accept remote server details to connect to .Any other API's that can be used for this purpose ?
If you have a specific web site name, you can use the WMI to stop and start that web site. If it's IIS as a whole, I'm sure there is something in the IIS WMI provider for doing this. Here I'm using WebAdministration to manage a web site under IIS, but there's also MicrosoftIISV2. Google for WmiExplorer, there are some good ones out there.
var connOptions = new ConnectionOptions();
connOptions.Authentication = AuthenticationLevel.PacketPrivacy;
// if you want to connect as someone other than logged in user
//connOptions.Username = username;
//connOptions.Password = password;
var scope = new ManagementScope("\\localhost\WebAdministration", connOptions);
WqlObjectQuery query = new WqlObjectQuery(`enter code here`string.Format("SELECT * FROM Site WHERE Name = '{0}'", "Default Web Site"));
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
{
foreach (ManagementObject site in searcher.Get())
{
ManagementBaseObject inParams = site.GetMethodParameters("Stop");
site.InvokeMethod("Stop", inParams, null);
ManagementBaseObject inParams2 = site.GetMethodParameters("Start");
site.InvokeMethod("Start", inParams2, null);
}
}

Uninstall application on remote computer silently

I am developing a C# program to remotely uninstall an application. It works fine but the problem is that it does not list all of the installed products on a particular selected computer.
The code for listing the installed product using WMI is :
void ListAllProducts()
{
try
{
ConnectionOptions connection = new ConnectionOptions();
connection.Username = Connect.UserName;
connection.Password = Connect.Password;
connection.Authority = "ntlmdomain:MSHOME";
ManagementScope scope = new ManagementScope("\\\\"+ Connect.MachineName +"\\root\\CIMV2", connection);
scope.Connect();
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_Product");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
System.Threading.Thread.Sleep(5000);
foreach (ManagementObject queryObj in searcher.Get())
{
listBox4.Items.Add(queryObj["Name"].ToString());
listBox2.Items.Add (queryObj["Name"].ToString ());
listBox1.Items.Add(queryObj["IdentifyingNumber"].ToString());
listBox3.Items.Add(queryObj["Version"].ToString());
}
}
catch (ManagementException e)
{
MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
}
}
The code for uninstalling all product is :
void UninstallProduct()
{
try
{
ConnectionOptions connection = new ConnectionOptions();
connection.Username = Connect.UserName;
connection.Password = Connect.Password;
connection.Authority = "ntlmdomain:MSHOME";
ManagementScope scope = new ManagementScope("\\\\"+Connect.MachineName +"\\root\\CIMV2", connection);
scope.Connect();
ManagementObject classInstance = new ManagementObject(scope, new ManagementPath ("Win32_Product.IdentifyingNumber='"+listBox1.Text +"',Name='"+listBox2.Text+"',Version='"+ listBox3.Text+"'"),null);
// no method in-parameters to define
// Execute the method and obtain the return values.
ManagementBaseObject outParams =
classInstance.InvokeMethod("Uninstall", null, null);
// List outParams
MessageBox.Show ("Uninstallation Starts");
}
catch(ManagementException err)
{
MessageBox.Show("An error occurred while trying to execute the WMI method: " + err.Message);
}
}
Please help me out to list all the products installed on the selected machine and to uninstall it without the consent of the user of that selected machine.
I believe your question relates to knowing which applications are installed on a remote machine. Once you know that, you can use your code to uninstall them. With that being the case, here is a link to an article on how to list all of the applications (with their uninstall information) on a remote computer:
http://mdb-blog.blogspot.com/2010/12/c-check-if-programapplication-is.html
The WMI Win32_Product only represents products that are installed by Windows Installer. To get a list of all installed products, you need to enumerate the subkeys of the SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall registry key. To do this remotely, you can use the WMI registry class StdRegProv class. TechNet includes sample scripts that show how this can be done, and which you can adapt to your particular needs:
How do I list all the installed applications on a given machine?
List Installed Software

Check if a process is running on a remote system using C#

I am trying to check if a process is running on a remote system. I am using the following code:
string procSearc = "notepad";
string remoteSystem = "remoteSystemName";
Process[] proce = System.Diagnostics.Process.GetProcessesByName(procSearch, remoteSystem);
However, when I try to run the code, I get the following error: "Couldn't connect to remote machine."
I am able to run pslist with the following command:
C:>pslist \remoteSystemName
So I know it is possible to get the information I need, but I need it in the code.
Another possibility would be to integrate pslist into C# and search the list to see if the process is there, but I have not found information on how to do this.
Use the System.ServiceProcess.ServiceController class for a service. You can use Status to check if it's running and the Stop() and Start() to control it.
ServiceController sc = new ServiceController();
sc.MachineName = remoteSystem;
sc.ServiceName = procSearc;
if (sc.Status.Equals(ServiceControllerStatus.Running))
{
sc.Stop();
}
else
{
sc.Start();
}
Below is what I did to get this to work:
First I added a reference to System.ServiceProcess and added: using System.ServiceProcess;
string remoteSystem = "remoteSystemName";
string procSearch = "notepad";
Process[] proc = System.Diagnostics.Process.GetProcessesByName(procSearch, remoteSystem);
if (proc.Length > 0)
{
Console.WriteLine("Able to find: " + proc[0]);
}
else
{
Console.WriteLine("Unable to find: " + procSearch);
}
Does the inner Exception say "Access Denied"?
A similar question may help, it mentions needing to be in the Performance Monitor Users group.
GetProcessesByName() and Windows Server 2003 scheduled task
I figured when running the application by itself I would get an exception window, because exceptions were not handled within my code...
There I saw the reason in the stacktrace: access denied. The reason was that the user running the program that was calling the .NET method to get the process list was not part of the "Performance Monitor Users" group of the remote machine.
After that I got another exception saying that the performance monitoring service was not running on the remote machine. So I started the corresponding service at the remote computer and voila it worked!
This was using a Windows 7 client trying to get the process list of a Windows 2008 Server.
Killing the remote process
I found that the Process.Kill() method does not work when the Process.MachineName has been set, so here is a solution for killing the process remotely, hope it helps others.
The extension method to create the method: KillRemoteProcess
public static class ProcessExtensions
{
public static void KillRemoteProcess(this Process p, string user, string password)
{
new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "TaskKill.exe",
Arguments = string.Format("/pid {0} /s {1} /u {2} /p {3}", p.Id, p.MachineName, user, password),
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true
}
}.Start();
}
}
And ofcourse the method to find the processes and consume the KillRemoteProcess
public static void KillProcessesRemote()
{
string targetProcessName = "myProcess"; //Do not put 'process.exe' here just 'process'
string targetMachine = "remotMachine"; //Target machine
string username = "myUser"; //Username
string password = "myPassword"; //Password
Parallel.ForEach<Process>( //Kill all processes found
source: System.Diagnostics.Process.GetProcessesByName(targetProcessName, targetMachine),
body: process => {
process.KillRemoteProcess(username, password);
});
}
You may try impersonate to the user that have access to the remote server.
https://learn.microsoft.com/en-us/dotnet/api/system.security.principal.windowsimpersonationcontext?redirectedfrom=MSDN&view=netframework-4.7.2
After Impersonation, you will no longer hit the error.
Also, you have to make sure there is trust between domain, else impersonation will not work.
LogonUser works only for my domain

Categories