2012-05-25 109 views
0

我使用PS 2.0,VS2010,C#使用C#调用Powershell脚本(ps1文件)。HostException执行使用C#的Powershell脚本

我有这个单元测试和工程罚款:

output = UsingPowerShell(@".\test1.ps1, ""); 
Assert.IsTrue(output.Contains("StringToBeVerifiedInAUnitTest")); 

脚本内容:

=================== test1.ps1 ========================== 
$someVariable = "StringToBeVerifiedInAUnitTest" 
$someVariable 
=================== End test1.ps1 ========================== 

但这个单元测试失败。我得到这个错误信息:

public static string UsingPowerShell(string scriptPS, string parametros) 
     { 
      if (string.IsNullOrWhiteSpace(parametros)) return UsingPowerShell(scriptPS, new List<string> { }); 
      return UsingPowerShell(scriptPS, parametros.Split(' ')); 
     } 

     public static string UsingPowerShell(string scriptPS, IList<string> parametros) 
     { 
      var builder = new StringBuilder(); 
      string answer = null; 

      RunspaceConfiguration rsConfig = RunspaceConfiguration.Create(); 
      InitialSessionState iss = InitialSessionState.CreateDefault(); 
      using (Runspace runspace = RunspaceFactory.CreateRunspace(iss)) 
      { 
       runspace.Open(); 

       //runspace.ApartmentState = System.Threading.ApartmentState.STA; 
       //runspace.ThreadOptions = PSThreadOptions.UseCurrentThread; 

       RunspaceInvoke runSpaceInvoker = new RunspaceInvoke(runspace); 
       runSpaceInvoker.Invoke("Set-ExecutionPolicy Unrestricted"); 

       // create a pipeline and feed it the script text 
       using (Pipeline pipeline = runspace.CreatePipeline()) 
       { 
        Command command = new Command(scriptPS,true,true); 
        foreach (var param in parametros) 
        { 
         command.Parameters.Add(null, param); 
        } 
        pipeline.Commands.Add(command); 

        //pipeline.Commands.AddScript(cmdArg); 
        //runspace.SessionStateProxy.SetVariable("MyResponse", response); 

        pipeline.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output); 

        Collection<PSObject> psresults = pipeline.Invoke(); 

        //PSObject newResponse = (PSObject)runspace.SessionStateProxy.GetVariable("MyResponse"); 

        //if you want to get a value from a variable in you script like so: 
        //Object resultcollection = runspace.SessionStateProxy.GetVariable("results"); 

        // convert the script result into a single string 
        var sb = new StringBuilder(); 
        foreach (PSObject obj in psresults) 
        { 
         sb.AppendLine(obj.ToString()); 
        } 


        answer = sb.ToString(); 
        Console.WriteLine(answer); 
        //Console.WriteLine(psresults.ToArray()[0].ToString()); 

        // check for errors (non-terminating) 
        if (pipeline.Error.Count > 0) 
        { 
         //iterate over Error PipeLine until end 
         while (!pipeline.Error.EndOfPipeline) 
         { 
          //read one PSObject off the pipeline 
          var value = pipeline.Error.Read() as PSObject; 
          if (value != null) 
          { 
           //get the ErrorRecord 
           var r = value.BaseObject as ErrorRecord; 
           if (r != null) 
           { 
            //build whatever kind of message your want 
            builder.AppendLine(r.InvocationInfo.MyCommand.Name + " : " + r.Exception.Message); 
            builder.AppendLine(r.InvocationInfo.PositionMessage); 
            builder.AppendLine(string.Format("+ CategoryInfo: {0}", r.CategoryInfo)); 
            builder.AppendLine(string.Format("+ FullyQualifiedErrorId: {0}", r.FullyQualifiedErrorId)); 
           } 
          } 
         } 
         //return builder.ToString(); 
        } 

        pipeline.Dispose(); 
       } 

       runspace.Close(); 
      } 

      return answer; 

     } 

 output = UsingPowerShell(@".\test2.ps1", ""); 
     Assert.IsTrue(output.Contains("test2.ps1")); 

脚本内容

=================== test2.ps1 ========================== 
$fullPathIncFileName = $MyInvocation.MyCommand.Definition 
$currentPath = $MyInvocation.MyCommand.Path 
$currentScriptName = $MyInvocation.MyCommand.Name 
$currentExecutingPath = $fullPathIncFileName.Replace($currentScriptName, "") 
$scriptDir = Split-Path -parent $MyInvocation.MyCommand.Path 

#Write-Host $currentExecutingPath 
Write-Host $currentScriptName 
Write-Host `r`nRuta: $scriptDir 
    =================== End test2.ps1 ========================== 

UsingPowerShell法“,因为当前的宿主,并不能实现它不能调用该函数”

有什么建议吗?

UPDATE:

如何的Windows PowerShell工作
http://msdn.microsoft.com/en-us/library/ms714658(VS.85).aspx

Windows PowerShell中暴露的命令行用户宿主应用程序(默认为powershell.exe)内运行,并使用一个主机接口与命令行调用的命令进行通信。托管应用程序可以是控制台应用程序,Windows应用程序或Web应用程序。在大多数情况下,托管应用程序使用其Main函数通过内部主机接口与Windows PowerShell运行时交互;然而,托管应用程序可以通过实现PSHost类以及一个或多个相关的用户界面类来选择性地支持自己的自定义主机。这些类一起允许应用程序和Windows PowerShell命令之间的直接通信。

回答

1

正在使用的PowerShell主机不支持写主机。

一个简单的解决方法是更换:

Write-Host $currentScriptName 
Write-Host `r`nRuta: $scriptDir 

由:

$currentScriptName 
"`r`nRuta: $scriptDir" 
+0

和其他解决方案?任何实施自定义PSHost的示例? – Kiquenet

+2

您可以编写一个函数Write-Host(实现您想要的功能)并将其放在脚本的顶部。 –