【问题标题】:VB.NET Process Standart Output redirect does not work on OpenSSH SCPVB.NET Process Standard 输出重定向在 OpenSSH SCP 上不起作用
【发布时间】:2022-02-02 09:58:24
【问题描述】:

当我将 OpenSSH SCP Executable 与 System.Diagnostics.Process 一起使用时,不以某种方式重定向标准输出

我正在使用托管的 Windows PC,并且必须将文件发送到仅受密码保护的 SFTP 服务器。由于我无法安装任何其他程序或库,因此我无法使用没有密码参数的 Windows 默认 OpenSSH 客户端。 PC 位于无法访问 Internet 的企业防火墙后面。但这就是我所坚持的。

我的方法是使用System.Diagnostics.Process 启动SCP 命令,监听密码提示,然后使用System.IO.StreamWriter 发送。

虽然这似乎确实适用于我听了ipconfig 并随后发送输入的测试用例,但我正在努力处理scpsftp 和其他程序,因为 DefaultOutput 似乎没有被重定向。

简化代码:

Private Dim Output = ""
Public Function CreateAndStartProcess(FileName As String, Optional Arguments As String = "")
  Dim targetProcess As New Process()
  targetProcess.StartInfo.FileName = FileName
  targetProcess.StartInfo.Arguments = Arguments
  targetProcess.StartInfo.UseShellExecute = False
  targetProcess.StartInfo.RedirectStandardInput = True
  targetProcess.StartInfo.RedirectStandardOutput = True
  targetProcess.StartInfo.CreateNoWindow = False
  
  targetProcess.Start()
  AddHandler targetProcess.OutputDataReceived, OutputHandler

  return targetProcess 
End Function

Sub OutputHandler(sender, e, process) //never gets called
  If String.IsNullOrEmpty(e.Data) Then
    Exit Sub
  End If

  Output = Output & Environment.NewLine & e.Data
End Sub

Dim targetProcess = CreateAndStartProcess("C:\\Windows\\Sysnative\\OpenSSH\\scp.exe", "C:\test.txt user@host:/test")
System.Threading.Thread.Sleep(2000) //just for simplification
Dim SW As System.IO.StreamWriter = targetProcess.StandardInput
SW.WriteLine("password")

 

当我在OutputHandler 中设置断点时,它永远不会被调用。执行后Output 字符串为空

我有什么遗漏吗?使用 ipconfig 时效果很好。

【问题讨论】:

    标签: vb.net scp system.diagnostics


    【解决方案1】:

    不确定你是如何编译的。您的输出处理程序的方法签名错误...

    根据您的 VB 代码,您可能正在尝试从 https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.outputdatareceived?view=net-6.0 重新创建 C# 示例

    我没有您尝试连接的任何主机,所以当它为我触发时,OutputHandler 是一个空字符串。但是,我在下面的代码中添加的 ErrorHandler 有来自该进程的输出。

    我建议阅读上面链接的文档。 我用来修改您的代码的示例代码中的几个关键点:

    1. 您必须调用 process.BeginOutputReadLine() 才能触发 OutputHandler 方法。

    2. 您需要调用 process.WaitForExit() 或设置 process.EnableRaiseEvents = True 并添加一个 Exit 事件处理程序,否则您永远不会知道进程何时结束。

    3. 仅当换行符(CR、LF 或 CR+LF)被发送到 StandardOutput 流时,才会调用输出事件处理程序。可能是那一行说“密码:”正在等待该行的输入,所以换行符已经发送,所以密码:还没有发送到我们的 OutputHandler。因此,您可能需要直接利用 StandardOutput 流来读取而不等待换行符,而不是使用 OutputHandler 方法。

    4. 您可能需要添加 ErrorHandler 方法(或类似的方法),以防您在 StandardError 流而不是输出流中收到错误消息。

       Sub Main()
           Dim targetProcess = CreateAndStartProcess("C:\\Windows\\Sysnative\\OpenSSH\\scp.exe", "C:\test.txt user@host:/test")
           targetProcess.BeginOutputReadLine()
           targetProcess.BeginErrorReadLine()
      
           Dim SW As System.IO.StreamWriter = targetProcess.StandardInput
           System.Threading.Thread.Sleep(2000) '//just For simplification
           SW.WriteLine("password")
      
           targetProcess.WaitForExit()
      
           If Not String.IsNullOrEmpty(Output) Then Console.WriteLine(Output)
           If Not String.IsNullOrEmpty(ErrorOutput) Then Console.WriteLine(ErrorOutput)
           targetProcess.WaitForExit()
           targetProcess.Close()
      
           Console.WriteLine(Environment.NewLine & Environment.NewLine & "Press any key to exit.")
           Console.ReadLine()
       End Sub
      
       Private Output As String = ""
       Private ErrorOutput As String = ""
       Public Function CreateAndStartProcess(FileName As String, Optional Arguments As String = "") As Process
           Dim targetProcess As New Process()
           targetProcess.StartInfo.FileName = FileName
           targetProcess.StartInfo.Arguments = Arguments
           targetProcess.StartInfo.UseShellExecute = False
           targetProcess.StartInfo.RedirectStandardInput = True
           targetProcess.StartInfo.RedirectStandardOutput = True
           targetProcess.StartInfo.RedirectStandardError = True
           targetProcess.StartInfo.CreateNoWindow = False
      
           AddHandler targetProcess.ErrorDataReceived, AddressOf ErrorHandler
           AddHandler targetProcess.OutputDataReceived, AddressOf OutputHandler
           targetProcess.Start()
      
           Return targetProcess
       End Function
      
       Sub OutputHandler(sender As Object, e As DataReceivedEventArgs) '//never gets called
           If String.IsNullOrEmpty(e.Data) Then
               Exit Sub
           End If
      
           Output = Output & Environment.NewLine & e.Data
       End Sub
      
       Sub ErrorHandler(sender As Object, e As DataReceivedEventArgs) '//never gets called
           If String.IsNullOrEmpty(e.Data) Then
               Exit Sub
           End If
      
           ErrorOutput = ErrorOutput & Environment.NewLine & e.Data
       End Sub
      

    【讨论】:

    • 我会尝试在星期一重新创建,处理程序签名是错误的,你是对的。这是我在简化 Stackoverflow 代码后的错误。你的解释完全有道理。我会尝试的,但为了那个很好的解释,你赢得了赏金:)
    猜你喜欢
    • 2018-12-03
    • 2012-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-02
    相关资源
    最近更新 更多