【问题标题】:C# process output redirection with plink (putty)C# 使用 plink (putty) 处理输出重定向
【发布时间】:2017-11-11 14:53:03
【问题描述】:

这个让我发疯...我想编写一个简单的 C# 应用程序(带有 GUI),通过 SSH 登录到我们的思科无线局域网控制器(短 WLC)并创建访客用户。如果不是 Cisco 出于某种原因决定不允许非交互式登录,这对于 SSH.NET 将非常容易——这意味着您不能传递用户名和密码,但必须在控制台中输入。更糟糕的是:他们在实际用户提示之前放置了一个额外的(非功能性)用户提示。上帝...

无论如何,我使用 plink.exe 解决了这个问题,它工作得很好,但是我想检查终端输出,以便确定某些命令是否正确执行。我也想使用输出登录,因为提示看起来有点慢,我不能依赖恒定的时间。

我找到了一些关于输出重定向的文章(例如Process.start: how to get the output?),但它只是不起作用。我只能在 plink.exe 关闭时收集输出,但我需要在 plink 仍在运行的情况下实时读取输出。

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

namespace WIFI
{
  public class Program
  {
    private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Application.Run(new myForm());
    }

    public static String ProcessInput(string user)
    {
        GlobalVar.hasError = false;
        GlobalVar.status = "";

        if (user.Length < 5 || user.Length > 10)
        {
            GlobalVar.status = "Username ungültig";
            GlobalVar.hasError = true;
        }
        else
        {
            WLCconnection WLC = new WLCconnection();
            WLC.ConnectWLC();

            if (!GlobalVar.hasError) WLC.UserExists(user);

            if (!GlobalVar.hasError) WLC.CreateUser(user);

            WLC.CloseWLC();
        }

        return GlobalVar.status;
    }
  }

  public static class GlobalVar
  {
    public static Boolean hasError;
    public static String status;
  }

  public class WLCconnection
  {
    Process terminal = new Process();
    StringBuilder terminalOutput = new StringBuilder();

    Boolean telnet = Convert.ToBoolean(System.Configuration.ConfigurationManager.AppSettings["telnet"]);
    String WLChostname = System.Configuration.ConfigurationManager.AppSettings["WLChostname"];
    String WLCusername = System.Configuration.ConfigurationManager.AppSettings["WLCusername"];
    String WLCpassword = System.Configuration.ConfigurationManager.AppSettings["WLCpassword"];

    public void ConnectWLC()
    {
        terminal.StartInfo.FileName = @System.Configuration.ConfigurationManager.AppSettings["plinkpath"];
        terminal.StartInfo.UseShellExecute = false;
        terminal.StartInfo.RedirectStandardInput = true;
        terminal.StartInfo.RedirectStandardOutput = true;
        terminal.StartInfo.RedirectStandardError = true;
        terminal.StartInfo.CreateNoWindow = true;

        if (telnet) terminal.StartInfo.Arguments = "-telnet " + WLChostname;
        else terminal.StartInfo.Arguments = "-ssh " + WLChostname;

        terminal.OutputDataReceived += (s, e) => terminalOutput.Append(e.Data);
        //terminal.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
        terminal.ErrorDataReceived += (s, e) => terminalOutput.Append(e.Data);
        //terminal.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);

        terminal.Start();
        terminal.BeginOutputReadLine();
        terminal.BeginErrorReadLine();

        int runs = 0;
        if (!telnet)
        {
            while (!terminalOutput.ToString().Contains("login as:") && !GlobalVar.hasError)
            {
                Thread.Sleep(500);
                if (runs < 20) runs++;
                else GlobalVar.hasError = true;
            }
            terminal.StandardInput.Write("workaroundSSHproblem\n");
        }

        runs = 0;
        while (!terminalOutput.ToString().Contains("User:") && !GlobalVar.hasError)
        {
            Thread.Sleep(500);
            if (runs < 20) runs++;
            else GlobalVar.hasError = true;
        }
        terminal.StandardInput.Write(WLCusername + "\n");

        runs = 0;
        while (!terminalOutput.ToString().Contains("Password:") && !GlobalVar.hasError)
        {
            Thread.Sleep(500);
            if (runs < 20) runs++;
            else GlobalVar.hasError = true;
        }
        terminal.StandardInput.Write(WLCpassword + "\n");
    }

    public void CloseWLC()
    {
        terminal.StandardInput.WriteLine("logout");
        terminal.WaitForExit();
        terminal.CancelOutputRead();
        terminal.Close();
        terminal.Dispose();
    }

    public Boolean UserExists(String user)
    {
        int runs = 0;
        while (!terminalOutput.ToString().Contains("(Cisco Controller) >") && !GlobalVar.hasError)
        {
            Thread.Sleep(500);
            if (runs < 20) runs++;
            else GlobalVar.hasError = true;
        }
        terminal.StandardInput.Write("show netuser detail " + user);

        if (!terminalOutput.ToString().Contains("blabla"))
        {
            GlobalVar.status = "User " + user + " bereits aktiviert";
            GlobalVar.hasError = true;
        }

        return GlobalVar.hasError;
    }

    public void CreateUser(String user)
    {
        int runs = 0;
        while (!terminalOutput.ToString().Contains("(Cisco Controller) >") && !GlobalVar.hasError)
        {
            Thread.Sleep(500);
            if (runs < 20) runs++;
            else GlobalVar.hasError = true;
        }
        terminal.StandardInput.Write("config netuser add " + user + " " + System.Configuration.ConfigurationManager.AppSettings["guestpassword"] + " wlan 3 userType guest lifetime 86400");

        if (!GlobalVar.hasError)
        {
            if (UserExists(user))
            {
                GlobalVar.status = "";
                GlobalVar.hasError = false;
            }
            else
            {
                GlobalVar.status = "User " + user + " konnte nicht aktiviert werden";
                GlobalVar.hasError = true;
            }

        }
    }

    protected void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
    {
        terminalOutput.Append(outLine.Data);
    }
  }
}

非常感谢您的帮助!

【问题讨论】:

  • 我不认为你可以用 Plink 做任何事情,而你不能用 SSH.NET 实现。
  • 谢谢@MartinPrikryl - 很高兴从该领域的专家那里听到这个消息(感谢您的出色工作!)。我对 SSH.NET 的问题是(看起来)用户和密码的输入在作为 command 传递时不被无线局域网控制器接受 - 这是 SSH.NET 可以传递的唯一方式任何输入AFAIK。因此,通过这种非常特殊的交互式用户登录实现,我无法使用 SSH.NET 成功登录。
  • 所以问一个关于 SSH.NET 的问题,而不是关于 Plink 的解决方法。

标签: c# redirect ssh process plink


【解决方案1】:

对谁有帮助:我再次使用 SSH.NET 解决了这个问题,但这次不是使用内置函数登录,而是结合使用 ShellStream 手动处理输入和输出。到目前为止工作得很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-05
    • 2018-04-14
    • 2011-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多