1

我无法在 C# 中使用 PowerShell 读取特定的注册表值。这是代码:

调用函数:

    public static string UserDisplayName()
    {
        // PowerShell Command: (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\SessionData\1').LoggedOnDisplayName
        return GetPowerShellOutputString(@"(Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\SessionData\1').LoggedOnDisplayName");
    }

函数定义:

    private static string GetPowerShellOutputString(string PsCmd)
    {
        try
        {
            string PsOut = string.Empty;
            Debug.Write("PsCmd: " + PsCmd + "; ");
            Runspace rs = RunspaceFactory.CreateRunspace();
            rs.Open();
            Pipeline pipeline = rs.CreatePipeline();
            pipeline.Commands.AddScript(PsCmd);
            Collection<PSObject> results = pipeline.Invoke();
            rs.Close();

            foreach (PSObject obj in results)
                if (obj != null) PsOut += obj.ToString() + ", ";

            PsOut = (PsOut == string.Empty) ? strUnavailableString : PsOut.TrimEnd(',', ' ');
            Debug.WriteLine("PsOut: " + PsOut);
            return PsOut;
        }
        catch (Exception ex)
        {
            Debug.WriteLine("! " + ex.Message + ex.InnerException + "\n");
            return strUnavailableString;
        }
    }

但是,如果我尝试读取任何其他注册表值,则相同的函数定义可以正常工作,例如:

    public static string UserOUPath()
    {
        try
        {
            if (UserDomain() == SystemInformation.ComputerName) return strUnavailableString; // Non-domain account

            //For consistant performance, grab OU from registry instead of AD.
            string userSID = WindowsIdentity.GetCurrent().User.ToString();
            string ouPath = @"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\" + userSID;
            string ou = GetPowerShellOutputString("(Get-ItemProperty -Path '" + ouPath + "').'Distinguished-Name'");

            ou = ou.Remove(0, ou.IndexOf(",", 0) + 1); // Drop leading CN stuff
            ou = ou.Remove(ou.IndexOf(",DC=", 0), ou.Length - ou.IndexOf(",DC=", 0)); // Drop trailing DC stuff
            ou = ou.Replace(",OU=", "/");
            ou = ou.Replace("OU=", "/");
            ou = FlipOU(ou);

            if (ou == null) throw new NullReferenceException();

            return ou;
        }
        catch
        {
            return strUnavailableString;
        }
    }

对于我在调试模式下的第一次调用 (UserDisplayName()),结果对象返回null。但是,如果我在 PowerShell 窗口中运行相同的 PowerShell 命令,它会给出值。

我偶然发现了这一点,因为我无法理解为什么以及发生了什么?

4

1 回答 1

0

有几件事。首先,我同意所有关于直接在 C# 中使用 Microsoft.Win32.Registry* 类的评论。但是,要回答有关从 PowerShell 执行此操作的问题,我相信您遇到了注册表虚拟化问题。如果您的 C# 项目是 AnyCPU 并在 Visual Studio 下运行,则它可能运行 32 位,并且该注册表路径将虚拟化为​​ SysWow64 注册表节点。所以你的注册路径将不存在。这可以通过将 exe 编译为 x64 来解决。另一种选择是使用 .NET Registry.OpenBaseKey() 方法将允许您指定要查看的注册表(32 位或 64 位)。

其次,您可以使用 PowerShell 类来简化代码,例如:

 var ps = PowerShell.Create();
 ps.AddScript(PsCmd);
 var results = ps.Invoke();
 foreach (PSObject obj in results)
     if (obj != null) PsOut += obj.ToString() + ", ";

第三,使用 PowerShell 类,在 Invoke() 调用之后,检查 Error 流中的错误,如下所示:

 foreach (var error in ps.Streams.Error)
     Console.Error.WriteLine(error);
于 2013-11-11T21:28:38.100 回答