I need to be able to read the values in a specific Registry Key from a list of Remote Computers. I can do this locally with the following code
using Microsoft.Win32;
RegistryKey rkey = Registry.LocalMachine;
RegistryKey rkeySoftware=rkey.OpenSubKey("Software");
RegistryKey rkeyVendor = rkeySoftware.OpenSubKey("VendorName");
RegistryKey rkeyVersions = rkeyVendor.OpenSubKey("Versions");
String[] ValueNames = rkeyVersions.GetValueNames();
foreach (string name in ValueNames)
{
MessageBox.Show(name + ": " + rkeyV开发者_开发百科ersions.GetValue(name).ToString());
}
but I don't know how to get the same info for a Remote Computer. Am I even using the right approach or should I be looking at WMI or something else?
You can achieve this through WMI, although I think you can also achieve it via the same mechanism (i.e. Microsoft.Win32 namespace classes) that you're currently using.
You need to look into the:
OpenRemoteBaseKey Method
The link above gives examples. It's should be as simple as something like:
// Open HKEY_CURRENT_USER\Environment
// on a remote computer.
environmentKey = RegistryKey.OpenRemoteBaseKey(
RegistryHive.CurrentUser, remoteName).OpenSubKey(
"Environment");
Note, though, that'll there will be security implications in opening remote registry keys, so you may need to ensure that you have the relevant security permissions to do this. For that, you'll want to look into the:
SecurityPermission
and
RegistryPermission
classes in the System.Security.Permissions
namespace.
I found that I could as CraigTP showed use the OpenRemoteBaseKey() method however it required me to change the permissions in the registry on the dest computers.
Here is the code I wrote that worked once I changed the permissions.
RegistryKey rkey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "RemoteComputer");
RegistryKey rkeySoftware = rkey.OpenSubKey("Software");
RegistryKey rkeyVendor = rkeySoftware.OpenSubKey("VendorName");
RegistryKey rkeyVersions = rkeyVendor.OpenSubKey("Versions");
String[] ValueNames = rkeyVersions.GetValueNames();
foreach (string name in ValueNames)
{
MessageBox.Show(name + ": " + rkeyVersions.GetValue(name).ToString());
}
I also found that I could get the same info using WMI without having to modify the permissions. Here is the code with WMI.
ManagementScope ms = new ManagementScope();
ms.Path.Server = "flebbe";
ms.Path.NamespacePath = "root\\default";
ms.Options.EnablePrivileges = true;
ms.Connect();
ManagementClass mc = new ManagementClass("stdRegProv");
mc.Scope = ms;
ManagementBaseObject mbo;
mbo = mc.GetMethodParameters("EnumValues");
mbo.SetPropertyValue("sSubKeyName", "SOFTWARE\\VendorName\\Versions");
string[] subkeys = (string[])mc.InvokeMethod("EnumValues", mbo, null).Properties["sNames"].Value;
ManagementBaseObject mboS;
string keyValue;
foreach (string strKey in subkeys)
{
mboS = mc.GetMethodParameters("GetStringValue");
mboS.SetPropertyValue("sSubKeyName", "SOFTWARE\\VendorName\\Versions");
mboS.SetPropertyValue("sValueName", strKey);
keyValue = mc.InvokeMethod("GetStringValue", mboS, null).Properties["sValue"].Value.ToString();
MessageBox.Show(strKey + " : " + keyValue);
}
P.S. I am calling the GetStringValue() method in the loop as I know all the values are strings. If there are multiple data types you would need to read the datatype from the Types output parameter of the EnumValues method.
This is the solution I went with in the end:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// add a reference to Cassia (MIT license)
// https://code.google.com/p/cassia/
using Microsoft.Win32;
namespace RemoteRegistryRead2
{
class Program
{
static void Main(string[] args)
{
String domain = "theDomain";
String user = "theUserName";
String password = "thePassword";
String host = "machine-x11";
using (Cassia.UserImpersonationContext userContext = new Cassia.UserImpersonationContext(domain + "\\" + user, password))
{
string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
System.Console.WriteLine("userName: " + userName);
RegistryKey baseKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, host);
RegistryKey key = baseKey.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName");
String computerName = key.GetValue("ComputerName").ToString();
Console.WriteLine(computerName);
}
}
}
}
Works like a charm :]
The win32 API allows you to specify a computer name through RegConnectRegistry. I'm not sure that the .NET wrappers exposes this. You can also use WMI as you mentioned.
Look up OpenRemoteBaseKey().
A commenter on my blog asked me to post my solution on stack overflow, so here it is.
How to authenticate and access the registry remotely using C#
It is basically the same as CraigTP's answer, but it includes a nice class for authenticating to the remote device.
And the code is in production and tested.
Easy example in c# installed programs via windows registry (remote: OpenRemoteBaseKey)
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace SoftwareInventory
{
class Program
{
static void Main(string[] args)
{
//!!!!! Must be launched with a domain administrator user!!!!!
Console.ForegroundColor = ConsoleColor.Green;
StringBuilder sbOutFile = new StringBuilder();
Console.WriteLine("DisplayName;IdentifyingNumber");
sbOutFile.AppendLine("Machine;DisplayName;Version");
//Retrieve machine name from the file :File_In/collectionMachines.txt
//string[] lines = new string[] { "NameMachine" };
string[] lines = File.ReadAllLines(@"File_In/collectionMachines.txt");
foreach (var machine in lines)
{
//Retrieve the list of installed programs for each extrapolated machine name
var registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (Microsoft.Win32.RegistryKey key = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, machine).OpenSubKey(registry_key))
{
foreach (string subkey_name in key.GetSubKeyNames())
{
using (RegistryKey subkey = key.OpenSubKey(subkey_name))
{
//Console.WriteLine(subkey.GetValue("DisplayName"));
//Console.WriteLine(subkey.GetValue("IdentifyingNumber"));
if (subkey.GetValue("DisplayName") != null)
{
Console.WriteLine(string.Format("{0};{1};{2}", machine, subkey.GetValue("DisplayName"), subkey.GetValue("Version")));
sbOutFile.AppendLine(string.Format("{0};{1};{2}", machine, subkey.GetValue("DisplayName"), subkey.GetValue("Version")));
}
}
}
}
}
//CSV file creation
var fileOutName = string.Format(@"File_Out\{0}_{1}.csv", "Software_Inventory", DateTime.Now.ToString("yyyy_MM_dd_HH_mmssfff"));
using (var file = new System.IO.StreamWriter(fileOutName))
{
file.WriteLine(sbOutFile.ToString());
}
//Press enter to continue
Console.WriteLine("Press enter to continue !");
Console.ReadLine();
}
}
}
精彩评论