2013-11-11 4 views
1

Я не могу прочитать определенные значения реестра с помощью PowerShell в C#. Вот код:Невозможно прочитать значение реестра с использованием PowerShell в C#

Вызов функции: определение

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, она дает значение.

Я наткнулся на это, поскольку я не могу понять, почему и что происходит?

+3

* «прочитайте определенные значения реестра, используя PowerShell в C#» * Вы что? Зачем? Не можете ли вы прочитать значения реестра с помощью методов C#? – Tomalak

+1

Я вижу это раз за разом здесь. Если вы работаете в C#, USE C# и это .net-классы. PowerShell медленный и сложный, и он использует те же .Net-классы, что вы можете получить доступ непосредственно к C# намного проще и быстрее. –

+0

Зачем вам это делать !? Вы передаете * PowerShell * скрипт в * C# *, который * уже имеет * намного лучшую функциональность для чтения значений реестра! Вы слишком усложняете это. – tnw

ответ

0

Несколько вещей. Сначала я согласен со всеми комментариями только о том, как использовать классы Microsoft.Win32.Registry * непосредственно в C#. Однако, чтобы ответить на ваш вопрос об этом с помощью 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(), проверьте поток ошибок на наличие ошибок, например так:

foreach (var error in ps.Streams.Error) 
    Console.Error.WriteLine(error); 
+0

Большое спасибо за вашу помощь. Я просто изменил цель платформы на x64 (от x86) и теперь работает. Хотя есть классы, доступные для чтения значения. Мне было просто интересно узнать причину этого случайного поведения. Теперь я могу хорошо выспаться сегодня вечером :-) – SavindraSingh

Смежные вопросы