Powershell 如何排除';系统。管理。自动化。CmdletInvocationException';

Powershell 如何排除';系统。管理。自动化。CmdletInvocationException';,powershell,msbuild,Powershell,Msbuild,有人知道如何最好地确定此异常的具体根本原因吗 考虑一个WCF服务,该服务应使用Powershell 2.0远程处理在远程计算机上执行MSBuild。在这两种情况下,脚本环境都是在进程中调用的(对于Powershell,通过C#调用,对于MSBuild,通过Powershell调用),而不是“剥离”——这是一个特定的设计决策,以避免命令行shell,并允许将实际对象传递到Powershell脚本中 调用MSBuild的Powershell脚本的简化版本如下所示: function Run-MSBu

有人知道如何最好地确定此异常的具体根本原因吗

考虑一个WCF服务,该服务应使用Powershell 2.0远程处理在远程计算机上执行MSBuild。在这两种情况下,脚本环境都是在进程中调用的(对于Powershell,通过C#调用,对于MSBuild,通过Powershell调用),而不是“剥离”——这是一个特定的设计决策,以避免命令行shell,并允许将实际对象传递到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代码如下所示(为了简单起见,删除了远程处理功能):

注意:Invoke()方法的重载允许您传入IEnumerable对象,它负责将枚举数实例化到Powershell变量“$input”中,然后通过管道将其传递到脚本中。以下是一些支持链接:

  • (跳转到“将输入对象传递到运行空间”部分)
假设问题与MSBuild输出Powershell运行空间无法处理的内容有关,我还尝试了第二个.Invoke()调用的以下变体:

请注意,无论是否使用输入对象,基本问题仍然会发生

我还研究了如何使用自定义PSHost(基于此示例:),但在调试期间,我看不到对它进行任何“有趣”的调用


Stackoverflow的优点和好处是否有任何洞察可以挽救我的理智?

我可以让以下代码正常工作,但我收到一条警告,MSBUILD引擎希望在STA线程上运行。不幸的是,PowerShell引擎为执行脚本而创建的线程是MTA。也就是说,我的小样本有效:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
using System.Collections;

namespace RunspaceInvokeExp
{
    class Program
    {
        static void Main()
        {
            var script = @"
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() 
} 
";
            using (var invoker = new RunspaceInvoke())
            {
                invoker.Invoke(script);
                IList errors;
                Collection<PSObject> results = invoker.Invoke(@"$input | Run-MSBuild", new[] {0}, out errors);
                Array.ForEach<PSObject>(results.ToArray(), Console.WriteLine);
            }
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Collections.ObjectModel;
使用System.Linq;
使用系统、管理、自动化;
使用系统集合;
命名空间RunspaceInvokeExp
{
班级计划
{
静态void Main()
{
变量脚本=@“
函数运行MSBuild
{ 
[System.Reflection.Assembly]::LoadWithPartialName(““Microsoft.Build.Engine”)
$engine=新对象Microsoft.Build.BuildEngine.engine
$engine.BinPath=”“C:\Windows\Microsoft.NET\Framework\v3.5“”
$project=新对象Microsoft.Build.BuildEngine.project($engine,“3.5”)
$project.Load(“'deploy.targets”“)
$project.InitialTargets=”“DoStuff“”
#处理输入对象
而($input.MoveNext())
{ 
#设置MSBuild属性和项
} 
#可选择设置一些记录器(也在没有任何记录器的情况下进行了尝试)
$consoleLogger=新对象Microsoft.Build.BuildEngine.consoleLogger
$engine.RegisterLogger($consoleLogger)
$fileLogger=新对象Microsoft.Build.BuildEngine.fileLogger
$fileLogger.Parameters=”“详细程度=诊断“”
$engine.RegisterLogger($fileLogger)
#运行生成-这是引发CmdleInvocationException的行
$result=$project.Build()
$engine.Shutdown()
} 
";
使用(var invoker=new RunspaceInvoke())
{
invoker.Invoke(脚本);
IList错误;
集合结果=invoker.Invoke(@“$input | Run MSBuild”,new[]{0},out errors);
ForEach(results.ToArray(),Console.WriteLine);
}
}
}
}
你的哪一行C代码失败了?另外,你可以发布一些异常的细节吗。您可以通过执行以下操作来解决MTA线程问题:

using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

namespace RunspaceInvokeExp
{
    class Program
    {
        [STAThread]
        static void Main()
        {
            var script = @"
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() 
} 

Run-MSBuild
";

            Runspace runspace = RunspaceFactory.CreateRunspace();
            Runspace.DefaultRunspace = runspace;
            runspace.Open();

            EngineIntrinsics engine = runspace.SessionStateProxy.
                GetVariable("ExecutionContext") as EngineIntrinsics;
            ScriptBlock scriptblock = 
                engine.InvokeCommand.NewScriptBlock(script);
            Collection<PSObject> results = scriptblock.Invoke(new[] { 0 });
            Array.ForEach<PSObject>(results.ToArray(), Console.WriteLine);

            runspace.Close(); // Really should be in a finally block
        }
    }
}
使用系统;
使用系统集合;
使用System.Collections.ObjectModel;
使用System.Linq;
使用系统、管理、自动化;
使用System.Management.Automation.Runspaces;
命名空间RunspaceInvokeExp
{
班级计划
{
[状态线程]
静态void Main()
{
变量脚本=@“
函数运行MSBuild
{ 
[System.Reflection.Assembly]::LoadWithPartialName(““Microsoft.Build.Engine”)
$engine=新对象Microsoft.Build.BuildEngine.engine
$engine.BinPath=”“C:\Windows\Microsoft.NET\Framework\v3.5“”
$project=新对象Microsoft.Build.BuildEngine.project($engine,“3.5”)
$project.Load(“'deploy.targets”“)
$project.InitialTargets=”“DoStuff“”
#处理输入对象
而($input.MoveNext())
{ 
#设置MSBuild属性和项
} 
#可选择设置一些记录器(也在没有任何记录器的情况下进行了尝试)
$consoleLogger=新对象Microsoft.Build.BuildEngine.consoleLogger
$engine.RegisterLogger($consoleLogger)
$fileLogger=新对象Microsoft.Build.BuildEngine.fileLogger
$fileLogger.Parameters=”“详细程度=诊断“”
$engine.RegisterLogger($fileLogger)
#运行生成-这是引发CmdleInvocationException的行
$result=$project.Build()
$engine.Shutdown()
} 
运行MSBuild
";
Runspace Runspace=RunspaceFactory.CreateRunspace();
Runspace.DefaultRunspace=运行空间;
Open();
EngineIntrinsics engine=runspace.SessionStateProxy。
GetVariable(“ExecutionContext”)作为EngineIntrinsics;
ScriptBlock脚本块=
engine.InvokeCommand.NewScriptBlock(脚本);
集合结果=scriptblock.Invoke(新[]{0});
ForEach(results.ToArray(),Console.WriteLine);
runspace.Close();//确实应该在finally块中
}
}
}

您能否提供有关在何处定义$input的更多详细信息?还有,看看哟
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
using System.Collections;

namespace RunspaceInvokeExp
{
    class Program
    {
        static void Main()
        {
            var script = @"
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() 
} 
";
            using (var invoker = new RunspaceInvoke())
            {
                invoker.Invoke(script);
                IList errors;
                Collection<PSObject> results = invoker.Invoke(@"$input | Run-MSBuild", new[] {0}, out errors);
                Array.ForEach<PSObject>(results.ToArray(), Console.WriteLine);
            }
        }
    }
}
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

namespace RunspaceInvokeExp
{
    class Program
    {
        [STAThread]
        static void Main()
        {
            var script = @"
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() 
} 

Run-MSBuild
";

            Runspace runspace = RunspaceFactory.CreateRunspace();
            Runspace.DefaultRunspace = runspace;
            runspace.Open();

            EngineIntrinsics engine = runspace.SessionStateProxy.
                GetVariable("ExecutionContext") as EngineIntrinsics;
            ScriptBlock scriptblock = 
                engine.InvokeCommand.NewScriptBlock(script);
            Collection<PSObject> results = scriptblock.Invoke(new[] { 0 });
            Array.ForEach<PSObject>(results.ToArray(), Console.WriteLine);

            runspace.Close(); // Really should be in a finally block
        }
    }
}