使用Plink.exe在C#中连接SSH进行测试

时间:2014-02-25 23:36:07

标签: c# ssh automation putty plink

我试图通过plink.exe连接到unix终端。目标是让我可以将文本读回字符串。

我的困境是我工作的银行使用的是我们通常通过腻子访问的旧的as400类型系统。我正在尝试开发一个自动化套件,它将与系统连接并运行作业并分析输出等。

所以我想我会通过C#使用plink。如果我通过命令提示符运行代码,我会得到(大致)我需要的文本。但是我在C#代码中遇到了问题,因为它只是挂起而且我从来没有得到过响应。

我想要的是这样的:

连接到服务器 输入命令 回读屏幕 //更多命令等

到目前为止,这是我的代码:

class Program
{
    static void Main(string[] args)
    {

        ProcessStartInfo psi = new ProcessStartInfo(@"C:\Windows\System32\cmd");
        psi.RedirectStandardInput = true;
        psi.RedirectStandardOutput = true;
        psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
        psi.UseShellExecute = false;
        psi.CreateNoWindow = false;

        Process process = Process.Start(psi);
        string cmdForTunnel = @"c:\putty\plink -ssh jonkers@bankhq -pw automationhero";
        process.StandardInput.WriteLine(cmdForTunnel);
       // process.WaitForExit();
        Thread.Sleep(30000);
        string output = process.StandardOutput.ReadToEnd();

        Console.WriteLine(output);

        //DoBusinessLogic();
        process.StandardInput.WriteLine("logout");
        Thread.Sleep(10000);

        if (process.HasExited)
        {
            process.Close();
            process.Dispose();
        } 
    }
}

我不确定问题在哪里,因为我说我已经通过命令行测试使用plink,但是我的解决方案只是挂起。我已经尝试在stackoverflow上使用其他人的解决方案,但它们似乎都没有为我工作,因为我不断得到这个挂起。非常感谢提示。

修改

我现在决定使用Renci Sharp SSH库并围绕此构建我自己的框架。它效果更好。

2 个答案:

答案 0 :(得分:10)

所以我只是想自己测试一下plink,结果很愉快。

正如我在评论中所说,您无法使用ReadToEnd 之前发送退出命令,除非您想阻止您的当前主题。

实际上你可以在使用exit之前发送一堆命令(包括logoutReadToEnd),但我确实建议执行Read asynchrounusly,因为它更健壮

现在有几种方法可以异步读取流。


Process类实际上提供了对传入数据引发的Events。您可以为Events创建处理程序。 这些事件是:

  • OutputDataReceived
  • ErrorDataReceived

他们的事件处理程序提供包含数据的字符串。


您可以使用stdout / stdin的BeginRead个实例的StreamReader

但是在这里我提供了一个代码示例,它使用简单的多线程以更粗糙的方式完成它:

  public string RequestInfo(string remoteHost, string userName, string password, string[] lstCommands) {
        m_szFeedback = "Feedback from: " + remoteHost + "\r\n";

        ProcessStartInfo psi = new ProcessStartInfo()
        {
            FileName = PLINK_PATH, // A const or a readonly string that points to the plink executable
            Arguments = String.Format("-ssh {0}@{1} -pw {2}", userName, remoteHost, password),
            RedirectStandardError = true,
            RedirectStandardOutput = true,
            RedirectStandardInput = true,
            UseShellExecute = false,
            CreateNoWindow = true
        };

        Process p = Process.Start(psi);

        m_objLock = new Object();
        m_blnDoRead = true;

        AsyncReadFeedback(p.StandardOutput); // start the async read of stdout
        AsyncReadFeedback(p.StandardError); // start the async read of stderr

        StreamWriter strw = p.StandardInput;

        foreach (string cmd in lstCommands)
        {
            strw.WriteLine(cmd); // send commands 
        }
        strw.WriteLine("exit"); // send exit command at the end

        p.WaitForExit(); // block thread until remote operations are done
        return m_szFeedback;
    }

    private String m_szFeedback; // hold feedback data
    private Object m_objLock; // lock object
    private Boolean m_blnDoRead; // boolean value keeping up the read (may be used to interrupt the reading process)

    public void AsyncReadFeedback(StreamReader strr)
    {
        Thread trdr = new Thread(new ParameterizedThreadStart(__ctReadFeedback));
        trdr.Start(strr);
    }
    private void __ctReadFeedback(Object objStreamReader)
    {
        StreamReader strr = (StreamReader)objStreamReader; 
        string line;          
        while (!strr.EndOfStream && m_blnDoRead) 
        {
            line = strr.ReadLine();
            // lock the feedback buffer (since we don't want some messy stdout/err mix string in the end)
            lock (m_objLock) { m_szFeedback += line + "\r\n"; }
        }
    }

因此,如果您想获取远程主机呼叫的用户目录的内容:

String feedback = RequestInfo("remote.ssh.host.de", "user", "password", new string[] { "ls -la" });

显然,您可以替换自己的地址,凭据和命令列表。

您也可能想要清理输出字符串。例如。在我的例子中,我发送到远程主机的命令被回显到输出中,因此出现在返回字符串中。

答案 1 :(得分:0)

嘿,上面的代码对我来说部分起作用但是我帮助我将juts替换为承包商参数如下

const string PLINK_PATH = @" C:\ Program Files(x86)\ PuTTY \ plink.exe&#34 ;;

        Process p = new Process();

        // Redirect the output stream of the child process.
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.RedirectStandardInput = true;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.RedirectStandardError = true;           
        p.StartInfo.FileName = PLINK_PATH;            
        p.StartInfo.Arguments = String.Format(" -ssh {0}@{1} -pw {2}", userName, remoteHost, password);

希望这对上面的代码有帮助....