我有以下代码片段,它从后端的 C# 文件运行。
using (Process process = new Process())
{
process.StartInfo.FileName = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
String cmd = "C:\\Users\\xyz\\AppData\\Local\\Temp\\2\\Demo.ps1";
process.StartInfo.Arguments = cmd;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = false;
process.StartInfo.RedirectStandardError = true;
StringBuilder error = new StringBuilder();
process.Start();
while (true)
{
bool hasExited = process.HasExited;
String errorStr = null;
while ((errorStr = process.StandardError.ReadLine()) != null)
error.AppendLine(errorStr);
if (hasExited)
break;
Thread.Sleep(100);
}
if (process.ExitCode != 0 || error.Length > 0)
throw new Exception(error.ToString());
}
演示.ps1
write-host "Working Properly now! "
我希望在同一个打开的 PowerShell 窗口中打印该字符串,但不知何故,它没有向打开的 PowerShell 窗口显示任何输出。如果我将输出重定向到文本文件,那么它就清晰可见。
问题是由于代码中 Process 类的设置方式造成的。具体来说,属性 UseShellExecute、RedirectStandardOutput 和 RedirectStandardError。
当您将 RedirectStandardOutput 或 RedirectStandardError 设置为 true 时,这意味着 C# 程序将分别捕获来自进程的输出或错误流。在您的例子中,您已将 RedirectStandardError 设置为 true,因此 C# 程序正在捕获错误流,但您已将 RedirectStandardOutput 设置为 false,这意味着未捕获输出流。
将 UseShellExecute 设置为 true。 将 RedirectStandardOutput 和 RedirectStandardError 设置为 false。 删除从 StandardError 读取的代码以及检查进程退出的循环。 这是修改后的代码:
要在 PowerShell 窗口中查看输出,您可以进行以下更改:
using (Process process = new Process())
{
process.StartInfo.FileName = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
String cmd = "-NoExit C:\\Users\\xyz\\AppData\\Local\\Temp\\2\\Demo.ps1"; // Added -NoExit to keep the PowerShell window open
process.StartInfo.Arguments = cmd;
process.StartInfo.UseShellExecute = true; // Changed to true
process.StartInfo.RedirectStandardOutput = false; // Remains the same
process.StartInfo.RedirectStandardError = false; // Changed to false
process.Start();
process.WaitForExit(); // Wait for the process to exit
}
cmd 中的 -NoExit 参数可确保 PowerShell 窗口在脚本完成后保持打开状态,以便您查看输出。如果删除它,窗口将在脚本执行后立即关闭。
此修改后的代码现在将打开一个新的 PowerShell 窗口并运行 Demo.ps1 脚本,在该窗口中显示输出。
C# 中直接有一个功能。它简化了交互,也更容易调试。
try
{
ScriptBuilder script = new ScriptBuilder();
script.LoadScript(File.ReadAllText(@"some.ps1"));
script.AddParameters(new Dictionary<string, string>
{
{"param1", "param1" }
});
script.Run();
System.Console.WriteLine("Hit any key to exit.");
System.Console.ReadKey();
}
catch (Exception ex)
{
System.Console.WriteLine(ex.Message);
}
这是一个简单的包装器
public class ScriptBuilder
{
private readonly PowerShell powerShellScript;
public ScriptBuilder()
{
powerShellScript = PowerShell.Create();
}
public void LoadScript(string script)
{
powerShellScript.AddScript(script);
}
public void AddParameters(Dictionary<string, string> parameters)
{
foreach (var parameter in parameters)
{
powerShellScript.AddParameter(parameter.Key, parameter.Value);
}
}
public void Run()
{
var output = new PSDataCollection<PSObject>();
output.DataAdded += Output_DataAdded;
powerShellScript
.BeginInvoke<PSObject, PSObject>(null, output)
.AsyncWaitHandle
.WaitOne();
powerShellScript.Invoke();
}
private static void Output_DataAdded(object? sender, DataAddedEventArgs e)
{
if (sender == null)
{
return;
}
PSObject newRecord = ((PSDataCollection<PSObject>)sender)[e.Index];
Console.WriteLine(newRecord);
}
}
此示例将参数传递给脚本并执行脚本。
这些是一些可以帮助进一步扩展代码的链接:
您观察到的行为是因为您将 PowerShell 作为具有不同输入和输出流的单独进程运行,并且 PowerShell 脚本生成的输出不会自动显示在父控制台窗口中。当您以这种方式运行 PowerShell 时,如果您想在父控制台中看到输出,则需要显式处理输出的重定向。
删除这一行 process.StartInfo.RedirectStandardOutput = false;从你的代码。此行告诉进程不要重定向标准输出。
修改 Demo.ps1 脚本以使用 Write-Output cmdlet 而不是 Write-Host。
Write-Output "Working Properly now !"
修改代码
using (Process process = new Process())
{
process.StartInfo.FileName = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
String cmd = "C:\\Users\\xyz\\AppData\\Local\\Temp\\2\\Demo.ps1";
process.StartInfo.Arguments = cmd;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
StringBuilder error = new StringBuilder();
process.Start();
while (true)
{
bool hasExited = process.HasExited;
String errorStr = null;
while ((errorStr = process.StandardError.ReadLine()) != null)
error.AppendLine(errorStr);
if (hasExited)
break;
Thread.Sleep(100);
}
if (process.ExitCode != 0 || error.Length > 0)
throw new Exception(error.ToString());
}