这是一个简单的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);
}
}
}
输出内容如下:
如果我们设置了运行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);
}
}
}
它引发以下异常:
让第二个程序输出服务名称的好方法是什么?
答案 0 :(得分:1)
您需要做更多的工作:
foreach (string str in PowerShell.Create().AddScript("Get-Service").AddCommand("Out-String").Invoke<string>())
{
Console.WriteLine(str);
}
答案 1 :(得分:1)
您的代码隐式调用.ToString()
发出的System.ServiceProcess.ServiceController
实例的Get-Service
方法,并且该.ToString()
方法的成员类型为ScriptMethod
,这意味着会在调用时执行脚本块,即一段 PowerShell 代码。
您可以通过交互式执行Get-Service | Get-Member ToString
问题在于,调用ScriptMethod
方法(以及ScriptProperty
属性)需要PowerShell runspace 来执行 PowerShell代码 >,并且以后您访问从.Invoke()
调用 C#代码返回的对象的成员(方法,属性)时,没有运行空间可用。
解决方法:
(a)作为您执行的 PowerShell代码的一部分调用成员,以便返回其 value 。
(b)避免使用C#代码中基于脚本的成员,并以不同的方式获得所需的信息。
using (var ps = PowerShell.Create(RunspaceMode.NewRunspace))
{
foreach (var svcName in ps.AddScript("(Get-Service).ForEach('ToString')").Invoke())
{
Console.WriteLine(svcName);
}
}
注意:
此解决方案的缺点是,您只能获取服务的名称,而不能获取描述它们的丰富对象。
使用.AddScript()
方法代替.AddCommand()
,因为它允许传递完整的PowerShell代码片段(脚本块)以执行。
.ForEach()
)传递给数组方法'ToString'
,它需要PSv4 +。在PSv3中,使用ForEach-Object
cmdlet。在您的情况下,.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
的{{1}}属性显式地访问包装的对象,该属性允许转换为实型。