Ваш код неявно вызывает метод .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*, которое позволяет приводить к реальному типу.