C#调用Powershell启用RedirectStandardInput后窗口空白无输出问题
问题根因
当你配置UseShellExecute = false且只开启RedirectStandardInput、未同步重定向标准输出和标准错误流时,PowerShell进程的输出内容会被写入系统默认的输出缓冲区,缓冲区占满后进程会直接阻塞,因此你看不到任何Write-Host输出,脚本也无法继续向下执行。如果关闭RedirectStandardInput,PowerShell会使用默认的交互式窗口处理输入输出,因此可以正常运行。
解决方案
分两种适用场景:
场景1:不需要在C#侧捕获PowerShell输出,只需窗口正常运行
优先选择参数化脚本的方案,避免使用标准输入传递参数,稳定性更高。
步骤1:修改PowerShell脚本,替换Read-Host为参数声明
param( [string]$user, [string]$pass, [string]$computerName ) $userPassword = ConvertTo-SecureString -String $pass -AsPlainText -Force $cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $user,$userPassword $pass = $null Write-Host "正在建立PSSession连接" # 非交互式场景建议用Invoke-Command执行远程操作,Enter-PSSession仅适合人工交互式使用 Invoke-Command -ComputerName $computerName -Credential $cred -ScriptBlock { # 此处填写需要在远程主机执行的命令 Write-Host "远程主机执行结果:当前主机名为 $env:COMPUTERNAME" } # 如果你确实需要保留交互式会话窗口,再保留以下代码 # Enter-PSSession -computername $computerName -Credential $cred
步骤2:修改C#代码,直接传递脚本参数
public void PssessionStart() { var scriptPath = @"C:\source\repos\TheTool\pssession.ps1"; // 拼接参数到启动命令中 var startArguments = $"-NoExit -ExecutionPolicy ByPass -File \"{scriptPath}\" -user \"{_elevatedUser}\" -pass \"{_elevatedPassword}\" -computerName \"{_connectedComputer}\""; Process p = Process.Start(new ProcessStartInfo() { FileName = "powershell", Arguments = startArguments, UseShellExecute = true, // 使用系统默认Shell启动,直接展示PowerShell窗口输出 }); p.WaitForExit(); }
场景2:必须通过标准输入向PowerShell传递参数
需要同步开启输出、错误流的重定向,并且主动读取流内容避免缓冲区阻塞:
public void PssessionStart() { var scriptPath = @"C:\source\repos\TheTool\pssession.ps1"; Process p = Process.Start(new ProcessStartInfo() { FileName = "powershell", Arguments = $"-NoExit -ExecutionPolicy ByPass -File \"{scriptPath}\"", UseShellExecute = false, RedirectStandardInput = true, // 同步开启输出、错误流重定向 RedirectStandardOutput = true, RedirectStandardError = true, // 若不需要显示PowerShell窗口,可开启以下配置 // CreateNoWindow = true }); // 注册输出、错误接收事件,主动读取流内容,避免缓冲区占满阻塞进程 p.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { // 此处可自定义输出逻辑,比如打印到C#控制台、写入日志等 Console.WriteLine($"[PowerShell输出] {e.Data}"); } }; p.ErrorDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { Console.WriteLine($"[PowerShell错误] {e.Data}"); } }; // 启动异步读取流 p.BeginOutputReadLine(); p.BeginErrorReadLine(); // 向标准输入写入参数 p.StandardInput.WriteLine(_elevatedUser); p.StandardInput.WriteLine(_elevatedPassword); p.StandardInput.WriteLine(_connectedComputer); p.WaitForExit(); }
注意事项
- 明文传递密码存在安全风险,生产环境建议使用更安全的凭据传递方式,避免明文出现在进程启动参数或日志中。
- 非自动化场景下,
Enter-PSSession仅适合人工交互式操作,程序调用时优先选择Invoke-Command执行指定的远程操作,避免进程无意义挂起。
内容的提问来源于stack exchange,提问作者Alexander Jonsson
相关产品推荐
相关产品推荐

