使用 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 命令之间的直接通信。
您正在使用的 powershell 主机不支持写入主机。
一个简单的解决方法是替换:
Write-Host $currentScriptName
Write-Host `r`nRuta: $scriptDir
由:
$currentScriptName
"`r`nRuta: $scriptDir"