You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 23:47:31