简体   繁体   English

HostException使用C#执行Powershell脚本

[英]HostException executing Powershell script using C#

I use PS 2.0, VS2010, C# for call Powershell scripts (ps1 files) using C#. 我使用PS 2.0,VS2010,C#使用C#调用Powershell脚本(ps1文件)。

I have this Unit Test and works fine: 我有这个单元测试,并且工作正常:

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

Script contents: 脚本内容:

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

But this Unit test fails. 但是此单元测试失败。 I get this error message: 我收到此错误消息:

"Cannot invoke this function because the current host does not implement it” “无法调用此功能,因为当前主机未实现此功能”

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

Script contents 脚本内容

    =================== 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 method: 使用PowerShell方法:

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;

        }

Any suggestions? 有什么建议么?

UPDATE: 更新:

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

Windows PowerShell operates within a hosting application (the default is powershell.exe) that exposes a command line to the user, and uses a host interface to communicate with the commands invoked by the command line. Windows PowerShell在宿主应用程序(默认为powershell.exe)内运行,该宿主应用程序向用户显示命令行,并使用主机界面与命令行调用的命令进行通信。 The hosting application can be a console application, a Windows application, or a Web application. 托管应用程序可以是控制台应用程序,Windows应用程序或Web应用程序。 In most cases, the hosting application uses its Main function to interact with the Windows PowerShell runtime through the internal host interface; 在大多数情况下,托管应用程序使用其Main函数通过内部主机界面与Windows PowerShell运行时进行交互。 however, a hosting application can optionally support its own custom host by implementing the PSHost class along with one or more related user interface classes. 但是,托管应用程序可以选择通过实现PSHost类以及一个或多个相关用户界面类来支持其自己的自定义主机。 Together, these classes allow direct communication between the application and Windows PowerShell commands. 这些类一起允许在应用程序和Windows PowerShell命令之间进行直接通信。

Write-host is not supported by the powershell host you are using. 您使用的Powershell主机不支持写主机。

An easy workaround is to replace: 一个简单的解决方法是替换:

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

by: 通过:

$currentScriptName
"`r`nRuta: $scriptDir"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM