使用 C# 执行 Powershell 脚本的 HostException

本文关键字:HostException 脚本 Powershell 执行 使用 | 更新日期: 2023-09-27 18:35:15

我使用 PS 2.0、VS2010、C# 使用 C# 调用 Powershell 脚本(ps1 文件)。

我有这个单元测试并且工作正常:

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

脚本内容:

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

但是此单元测试失败。我收到此错误消息:

"无法调用此函数,因为当前主机未实现它"

        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 ==========================

使用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;
        }

有什么建议吗?

更新:

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 命令之间的直接通信。

使用 C# 执行 Powershell 脚本的 HostException

您正在使用的 powershell 主机不支持写入主机。

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

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

由:

$currentScriptName
"`r`nRuta: $scriptDir"