【发布时间】:2011-02-07 20:04:39
【问题描述】:
有谁知道如何最好地确定此异常的具体根本原因?
考虑一个 WCF 服务,它应该使用 Powershell 2.0 远程处理在远程计算机上执行 MSBuild。在这两种情况下,脚本环境都在进程内调用(通过 C# 用于 Powershell,通过 Powershell 用于 MSBuild),而不是“shelling-out”——这是避免命令行地狱以及启用传递的特定设计决策将实际对象放入 Powershell 脚本中。
调用 MSBuild 的 Powershell 脚本的精简版如下所示:
function Run-MSBuild
{
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Build.Engine")
$engine = New-Object Microsoft.Build.BuildEngine.Engine
$engine.BinPath = "C:\Windows\Microsoft.NET\Framework\v3.5"
$project = New-Object Microsoft.Build.BuildEngine.Project($engine, "3.5")
$project.Load("deploy.targets")
$project.InitialTargets = "DoStuff"
# Process the input object
while ($input.MoveNext())
{
# Set MSBuild Properties & Item
}
# Optionally setup some loggers (have also tried it without any loggers)
$consoleLogger = New-Object Microsoft.Build.BuildEngine.ConsoleLogger
$engine.RegisterLogger($consoleLogger)
$fileLogger = New-Object Microsoft.Build.BuildEngine.FileLogger
$fileLogger.Parameters = "verbosity=diagnostic"
$engine.RegisterLogger($fileLogger)
# Run the build - this is the line that throws a CmdletInvocationException
$result = $project.Build()
$engine.Shutdown()
}
从 PS 命令提示符运行上述脚本时,一切正常。但是,一旦从 C# 执行脚本,它就会失败并出现上述异常。
用于调用 Powershell 的 C# 代码如下所示(为简单起见,删除了远程功能):
// Build the DTO object that will be passed to Powershell
dto = SetupDTO()
RunspaceConfiguration runspaceConfig = RunspaceConfiguration.Create();
using (Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfig))
{
runspace.Open();
IList errors;
using (var scriptInvoker = new RunspaceInvoke(runspace))
{
// The Powershell script lives in a file that gets compiled as an embedded resource
TextReader tr = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("MyScriptResource"));
string script = tr.ReadToEnd();
// Load the script into the Runspace
scriptInvoker.Invoke(script);
// Call the function defined in the script, passing the DTO as an input object
var psResults = scriptInvoker.Invoke("$input | Run-MSBuild", dto, out errors);
}
}
注意:Invoke() 方法的重载允许您传入一个 IEnumerable 对象,它负责在 Powershell 变量 '$input' 中实例化一个枚举器 - 然后通过管道将其传递到脚本中。以下是一些支持链接:
- http://msdn.microsoft.com/en-us/library/ms569104(VS.85).aspx
- http://knicksmith.blogspot.com/2007/03/managing-exchange-2007-recipients-with.html(跳转到“将输入对象传递给运行空间”部分)
假设问题与 MSBuild 输出 Powershell 运行空间无法处理的内容有关,我还尝试了对第二个 .Invoke() 调用的以下变体:
var psResults = scriptInvoker.Invoke("$input | Run-MSBuild | Out-String", dto, out errors);
var psResults = scriptInvoker.Invoke("$input | Run-MSBuild | Out-Null", dto, out errors);
var psResults = scriptInvoker.Invoke("Run-MSBuild | Out-String");
var psResults = scriptInvoker.Invoke("Run-MSBuild | Out-String");
var psResults = scriptInvoker.Invoke("Run-MSBuild | Out-Null");
var psResults = scriptInvoker.Invoke("Run-MSBuild");
请注意,无论是否使用输入对象,潜在问题仍然存在。
我还研究过使用自定义 PSHost(基于此示例:http://blogs.msdn.com/daiken/archive/2007/06/22/hosting-windows-powershell-sample-code.aspx),但在调试过程中我无法看到对其进行的任何“有趣”调用。
Stackoverflow 的优点和优点是否有任何见解可以挽救我的理智?
【问题讨论】:
-
您能否提供更多关于您在何处定义 $input 的详细信息?另外,查看您的 Run-MSBuild 函数,我没有遵循它应该如何允许管道输入 ($input|run-msbuild)。
-
嗨,马可,感谢您的评论。我已经添加了一些关于此的更多信息,但是,无论是否使用输入对象,问题都存在。
标签: powershell msbuild