2016-08-03 2 views
0

Я немного странный. Мне предоставлен довольно большой набор модулей и функций PowerShell, и моя работа - связать их вместе с исполняемым файлом. В требованиях указано, что это должен быть отдельный автономный исполняемый файл без установщика, а .net 3.5 может быть единственной зависимостью. Рамки управления Windows не являются исключением и не могут считаться существующими на машине. Чтобы обойти это, я добавил System.Management.Automation в качестве ссылки и сделал его встроенным ресурсом вместе со всеми файлами модулей PowerShell и загрузил их из отражения во время выполнения. Кажется, это работает нормально, но у меня есть некоторые ошибки, которые я не могу понять, и думаю, что это может иметь какое-то отношение к этой системе.C#: ArgumentException при вызове System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace()

Итак, вот проблема: когда я начинаю инициализировать вещи для запуска команды PowerShell, я получаю странную ошибку, которую я не могу контролировать.

Вот код:

public static void RunCommand(object objcommand) 
    { 
     //create a script block for toolbox once, get the embeded resource, convert from byte array to string, make scriptblock from string 
     ScriptBlock toolbox = System.Management.Automation.ScriptBlock.Create(System.Text.Encoding.Default.GetString(Properties.Resources.toolbox)); 
     string command = (string)objcommand; 
     //get the module name 
     string modname = options.Commands[command]["module"]; 
     //get the module from the embeded resources, convert to string, convert to scriptblock 
     var module = System.Management.Automation.ScriptBlock.Create(new System.IO.StreamReader(myasm.GetManifestResourceStream("piramids.Resources." + modname + ".psm1")).ReadToEnd()); 
     using (var powerShell = PowerShell.Create()) 
     { 
      System.Management.Automation.Runspaces.Runspace rs = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(); //i think this line triggers the exception 
      rs.Open(); 
      powerShell.Runspace = rs; 


      //make the necesary powershell modules of the command availible 
      powerShell.AddCommand("new-module").AddParameter("ScriptBlock", toolbox).Invoke(); 
      powerShell.AddCommand("new-module").AddParameter("ScriptBlock", module).Invoke(); 


      //if inethistory, make dlls availible 
      if (modname.Equals("inethistory")) 
      { 
       powerShell.AddCommand("add-type").AddParameter("Path", sqldll).Invoke(); 
       powerShell.AddCommand("add-type").AddParameter("Path", esentdll).Invoke(); 
      } 



      ICollection<PSObject> output = new List<PSObject>(0); 
      try { 
       output = powerShell.AddCommand("get-" + command).AddCommand(format).AddCommand("out-string").Invoke();//pipeline.Invoke(); 
      } catch (System.Management.Automation.RuntimeException e) 
      { 
       Console.Error.WriteLine("An Error occured while executing '" + command + "'"); 
       Console.Error.WriteLine(e.Message); 
      } 
     //do stuff with the results 

и вот трассировки стека:

Unhandled Exception: System.ArgumentException: The path is not of a legal form. 
    at System.IO.Path.NormalizePathFast(String path, Boolean fullCheck) 
    at System.IO.Path.NormalizePath(String path, Boolean fullCheck) 
    at System.IO.Path.GetFullPathInternal(String path) 
    at System.IO.Path.GetFullPath(String path) 
    at System.Diagnostics.FileVersionInfo.GetFullPathWithAssert(String fileName) 
    at System.Diagnostics.FileVersionInfo.GetVersionInfo(String fileName) 
    at System.Management.Automation.PSVersionInfo.GetPSVersionTable() 
    at System.Management.Automation.PSVersionInfo.get_PSVersion() 
    at Microsoft.PowerShell.DefaultHost..ctor(CultureInfo currentCulture, CultureInfo currentUICulture) 
    at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace() 
    at piramids.Program.RunCommand(Object objcommand) 
    at piramids.Program.Main(String[] args) 

Я считаю, что эта линия, где происходит исключение:

System.Management.Automation.Runspaces.Runspace rs = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(); 

Метод CreateRunspace не задокументировано, чтобы выбросить какие-либо исключения, и это исключение исходит из стольких уровней, что я не знаю, что вид пути, который эта вещь проверяет, поскольку я никогда не вызывал функцию, которая запрашивала путь.

Я в тупик. Кто-нибудь знает, что может быть причиной этого?

EDIT: После некоторого рытья, вот что я нашел. PSVersionTable является статическим полем VersionInfo, поэтому статический конструктор называется первым вызовом, вызываемым для этого поля. Статический конструктор вызывает внутренний метод GetBuildVersion, который пытается получить местоположение сборки PSVersionInfo. Согласно This documentation page:

Если сборка загружается из массива байтов, например, при использовании нагрузки (байт []) метод перегрузки, возвращаемое значение является пустая строка («»).

Я загружаю из массива байтов, поэтому это будет пустая строка. Но тогда GetBuildVersion использует это местоположение для выполнения FileVersionInfo.GetVersionInfo, который проверяет путь с Path.GetFullPath. По This documentation page:

ArgumentException:
путь нулевой длины строки

Так что есть проблема. Теперь встает вопрос: как назначить местоположение сборке, загруженной из массива байтов? Пусть Бог помилует меня.

+0

Какая строка вызывает исключение? – briantist

+0

извините, этот: System.Management.Automation.Runspaces.Runspace rs = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(); – Sandles

+0

Использование рефлектора в GetPSVersionTable() дает: "string location = Assembly.GetExecutingAssembly(). Location; string fileVersion = FileVersionInfo.GetVersionInfo (location) .FileVersion;". Выполняется ли ваша программа из «специального» местоположения? –

ответ

0

Я совсем не убежден, что это даже отдаленно разумно ожидать, что код PowerShell будет работать без установки WMF. Если бы я был обращен к этому запросу, я бы ответил, что весь код должен быть перестроен на другом языке .NET (то есть C#).

Тем не менее, возможно, вы можете видеть, является ли это статическим методом. Вы должны будете де-PowerShell код, который я боюсь. Ускоритель PowerShell - это просто простой способ получить доступ к сборке System.Management.Automation.Класс не является общедоступным, и метод класса не является общедоступным.

$ verInfo = [PowerShell] .Assembly.GetTypes() | Where-Object Name -eq 'PSVersionInfo' $ verInfo.GetMethod ('get_PSVersion', [System.Reflection.BindingFlags] 'NonPublic, Static'). Invoke ($ null, [System.Reflection.BindingFlags] 'NonPublic, Static' , $ null, @(), $ null)

Chris

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