SSH代理场景下PowerShell标准IO二进制无编码传输问题求助
如何让PowerShell实现标准输入输出的二进制数据1:1转发?
问题场景
通过SSH ProxyCommand搭建隧道时,等价逻辑的.NET可执行程序能正常转发标准输入输出到TCP套接字,但PowerShell脚本却导致SSH频繁报告数据包大小异常。核心需求是让PowerShell不对数据做编码转换,保持二进制原样转发。
原SSH配置
Host XXYYZZWW User server HostName 127.0.0.1 Port 2222 StrictHostKeyChecking no NumberOfPasswordPrompts 0 PasswordAuthentication no BatchMode yes IdentityFile ~/.ssh/id_rsa ProxyCommand powershell -File D:/Workspaces/liquid/maintenancw/rustdesk-ssh.ps1 -LocalPort 2222 -RemotePort 22 -RemoteHost 127.0.0.1 -RustdeskId XXYYZZWW
原PowerShell脚本代码
param ($RustdeskId, $IdentityFile, $User, $LocalPort, $RemotePort, $RemoteHost, $RemoteUser) $def = @"`nusing System.Net;`nusing System.IO;`nusing System.Diagnostics;`nusing System.Threading;`nusing System;`n public class MyClass {`n public void Run() {`n var tcpClient = new System.Net.Sockets.TcpClient("localhost", 2222);`n tcpClient.NoDelay = true;`n var tcpStream = tcpClient.GetStream();`n var stdin = System.Console.OpenStandardInput();`n var stdout = System.Console.OpenStandardOutput();`n System.Threading.Tasks.Task.WaitAll(stdin.CopyToAsync(tcpStream, 1024), tcpStream.CopyToAsync(stdout, 1024));`n }`n}`n"@`n Add-Type -TypeDefinition $def`n$obj = New-Object MyClass`n$obj.Run()`n
问题根源
PowerShell宿主环境默认会对标准输入输出流执行编码转换(比如默认使用UTF-8或系统OEM编码),即使脚本中调用.NET的Console.OpenStandardInput()/OpenStandardOutput(),获取的流也已经经过PowerShell的编码处理,导致二进制数据被篡改。而独立.NET程序直接操作原始系统流,没有这个问题。
解决方案
方案1:直接用powershell -Command执行内嵌C#代码
绕过PowerShell脚本文件的编码处理,直接在ProxyCommand中执行内嵌的C#逻辑,让.NET直接获取原始二进制流:
Host XXYYZZWW User server HostName 127.0.0.1 Port 2222 StrictHostKeyChecking no NumberOfPasswordPrompts 0 PasswordAuthentication no BatchMode yes IdentityFile ~/.ssh/id_rsa ProxyCommand powershell -Command "$def = @' using System.Net.Sockets; using System.IO; using System.Threading.Tasks; public static class SshProxy { public static void Run() { using var tcpClient = new TcpClient("localhost", 2222); tcpClient.NoDelay = true; using var tcpStream = tcpClient.GetStream(); using var stdin = System.Console.OpenStandardInput(); using var stdout = System.Console.OpenStandardOutput(); // 使用更大的缓冲区提升性能,避免小数据包频繁传输 Task.WaitAll(stdin.CopyToAsync(tcpStream, 4096), tcpStream.CopyToAsync(stdout, 4096)); } } '@; Add-Type -TypeDefinition $def; [SshProxy]::Run()"
方案2:修改脚本,强制PowerShell使用二进制模式
如果必须使用脚本文件,需要在脚本开头添加以下代码(仅适用于PowerShell 7+),减少编码转换的影响:
# 强制标准输入输出使用无转换的编码模式 [Console]::InputEncoding = [System.Text.Encoding]::ASCII [Console]::OutputEncoding = [System.Text.Encoding]::ASCII # PowerShell 7.2+可直接使用Raw编码 $PSDefaultParameterValues['*:Encoding'] = 'Raw'
但这种方式仍有概率受PowerShell宿主环境干扰,优先推荐方案1。
关键说明
- 使用
powershell -File运行脚本时,PowerShell会先将输入流解码为字符串再传递给.NET代码,导致二进制数据中的非文本字节被破坏。 - 直接用
-Command执行内嵌C#代码时,.NET的Console.OpenStandardInput()会直接绑定到SSH提供的原始系统流,不会经过PowerShell的编码转换,完美实现二进制数据1:1转发。
内容的提问来源于stack exchange,提问作者Lawrence Kok
相关产品推荐
相关产品推荐

