2012-05-25 106 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(實現您想要的功能)並將其放在腳本的頂部。 –