如何读取远程注册表键?

13

我需要能够从一组远程计算机中读取特定注册表键中的值。本地可以使用以下代码实现:

   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 + ": " + rkeyVersions.GetValue(name).ToString());
        }

但我不知道如何获取远程计算机的相同信息。 我是否在使用正确的方法,还是应该查看WMI或其他内容?


1
你考虑过使用WMI吗? - Nathan Taylor
7个回答

15
你可以通过 WMI 实现这个功能,不过我认为你也可以通过你目前正在使用的相同机制(即 Microsoft.Win32 命名空间类)来实现它。你需要查看:OpenRemoteBaseKey 方法。上面的链接提供了示例。它应该很简单,就像这样:
// Open HKEY_CURRENT_USER\Environment 
// on a remote computer.
environmentKey = RegistryKey.OpenRemoteBaseKey(
                   RegistryHive.CurrentUser, remoteName).OpenSubKey(
                   "Environment");
请注意,打开远程注册表键会产生安全风险,因此您可能需要确保具有执行此操作的相关安全权限。为此,您需要查看:SecurityPermissionRegistryPermission 类在System.Security.Permissions命名空间中。

1
接受这个答案并在下面的回复中提供更多关于我如何使用它解决我的问题的信息。 - etoisarobot

11

我发现可以像CraigTP展示的那样使用OpenRemoteBaseKey()方法,但这需要我在目标计算机上更改注册表中的权限。

这是我写的代码,在更改权限后成功运行。

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());
}

我还发现可以使用WMI获取相同的信息,而无需修改权限。以下是使用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);
}

顺便说一句,我在循环中调用了GetStringValue()方法,因为我知道所有的值都是字符串。如果有多个数据类型,你需要从EnumValues方法的Types输出参数中读取数据类型。


你更改了哪些权限以使“OpenRemoteBaseKey”正常工作?谢谢! - marsh-wiggle

2
这是我最终采用的解决方案:
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);
            }
        }
    }
}

运作得很好:]

1

通过Windows注册表(远程:OpenRemoteBaseKey)安装程序的C#简单示例

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();
        }


    }
}

获取错误:'不允许请求注册表访问权限。' - Prashant Kumar
控制台应用程序必须使用域管理员用户启动。 - Domenico Zinzi

1
win32 API允许您通过RegConnectRegistry指定计算机名称。我不确定.NET包装器是否公开了这一点。您还可以像您提到的那样使用WMI。

1

查找OpenRemoteBaseKey()。


1
我的博客上的一位评论者要求我在Stack Overflow上发布我的解决方案,所以这里是它。 如何使用C#进行远程身份验证和访问注册表 基本上与CraigTP的答案相同,但它包括一个用于对远程设备进行身份验证的好类。
而且代码已经在生产环境中测试过。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接