Запуск Get-Service с хоста C # - PullRequest
2 голосов
/ 08 мая 2019

Вот простая хост-программа C # PowerShell, которая просто запускает Get-ChildItem и отображает результаты на консоли:

using System.Management.Automation;

using static System.Console;

namespace PsHostGetChildItem
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = PowerShell.Create().AddCommand("Get-ChildItem")
                .AddParameter("Path", @"c:\Windows")
                .AddParameter("Filter", "*.exe")
                .Invoke();

            foreach (var elt in result)
                WriteLine(elt);
        }
    }
}

Вот как выглядит результат:

enter image description here

Если мы настроим аналогичную программу, которая запускает Get-Service:

using System.Management.Automation;

using static System.Console;

namespace PsHostGetService
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = PowerShell.Create().AddCommand("Get-Service").Invoke();

            foreach (var elt in result)
                WriteLine(elt);
        }
    }
}

, она выдаст следующее исключение:

enter image description here

Каков хороший способ, чтобы вторая программа выводила имена сервисов?

Ответы [ 2 ]

1 голос
/ 08 мая 2019

Ваш код неявно вызывает метод .ToString() экземпляров System.ServiceProcess.ServiceController, которые Get-Service испускает, и этот метод .ToString() имеет тип члена ScriptMethod, что означает, что он выполняет блок сценария , то есть фрагмент кода PowerShell , при вызове.

Это можно увидеть в интерактивном режиме Get-Service | Get-Member ToString

Проблема заключается в том, что для вызова ScriptMethod методов (а также ScriptProperty свойств) требуется PowerShell runspace для выполнения кода PowerShell in и отсутствие пространства выполнения доступно, когда вы позднее получаете доступ к членам (методам, свойствам) для объектов, возвращаемых из .Invoke() вызова в C # коде .

Обходные

  • (a) Вызовите участника как часть кода PowerShell , который вы выполняете, так что возвращается значение .

  • (b) Избегайте основанных на сценариях членов в коде C # и получайте необходимую информацию по-другому.


(a) Вызов основанных на сценариях членов в коде PowerShell:

using (var ps = PowerShell.Create(RunspaceMode.NewRunspace))
{
  foreach (var svcName in ps.AddScript("(Get-Service).ForEach('ToString')").Invoke()) 
  {
    Console.WriteLine(svcName);
  }
}

Примечание:

  • Недостатком этого решения является то, что вы получаете только имена сервисов, а не богатые объекты, описывающие их.

  • Вместо .AddCommand() используется метод .AddScript(), поскольку он позволяет передавать для выполнения целые фрагменты кода PowerShell (блоки скриптов).

    • Метод массива .ForEach(), которому передается имя метода ('ToString') для выполнения на каждом элементе, требует PSv4 +; в PSv3- используйте командлет ForEach-Object.

(b) Избегание основанных на сценариях членов в коде C #:

В вашем случае .ToString() просто возвращает значение свойства .ServiceName, поэтому вы можете получить значение этого свойства напрямую:

using (var ps = PowerShell.Create())
{
  foreach (var svc in ps.AddCommand("Get-Service").Invoke()) 
  {
    Console.WriteLine(((dynamic) svc).ServiceName);

    // Alternatively, use an explicit cast from .BaseObject:
    // Console.WriteLine(
    //   ((System.ServiceProcess.ServiceController) svc.BaseObject).ServiceName
    // );
  }
}

Обратите внимание на необходимость приведения к dynamic для доступа к свойствам System.ServiceProcess.ServiceController экземпляров, которые обернуты PSObject экземплярами, возвращаемыми .Invoke().

В качестве альтернативы, к обернутому объекту также можно получить явный доступ через свойство PSObject *1089*, которое позволяет приводить к реальному типу.

1 голос
/ 08 мая 2019

Вам нужно сделать немного больше, чтобы это работало:

foreach (string str in PowerShell.Create().AddScript("Get-Service").AddCommand("Out-String").Invoke<string>())
{
    Console.WriteLine(str);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...