Перенаправление вывода процесса С# с помощью plink (putty)

Это сводит меня с ума ... Я хочу написать простое приложение C # (с графическим интерфейсом), которое входит в наш контроллер беспроводной локальной сети Cisco (сокращенно WLC) через SSH и создает гостевых пользователей. Это было бы довольно просто с SSH.NET, если бы Cisco по какой-либо причине не решила не разрешать неинтерактивный вход в систему — это означает, что вы не можете передать имя пользователя и пароль, а должны ввести их на консоли. Еще хуже: они помещают дополнительную (нефункциональную) подсказку пользователя перед фактической подсказкой пользователя. Бог...

Во всяком случае, я понял это с помощью plink.exe, и он работает вполне нормально, однако я хочу проверить вывод терминала, чтобы решить, правильно ли были выполнены некоторые команды. Я также хочу использовать вывод для входа в систему, так как приглашение выглядит несколько медленным, и я не могу полагаться на постоянное время.

Я нашел несколько статей о перенаправлении вывода (например, Process.start: как получить результат?), но он просто не работает. Я смог собрать вывод только тогда, когда 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);
    }
  }
}

Я был бы очень признателен за вашу помощь!


person Ryan Hardy    schedule 11.11.2017    source источник
comment
Я не думаю, что с Plink можно сделать что-то, чего нельзя реализовать с помощью SSH.NET.   -  person Martin Prikryl    schedule 11.11.2017
comment
Спасибо @MartinPrikryl - рад слышать это от эксперта в этой области (и спасибо за вашу прекрасную работу!). Моя проблема с SSH.NET заключается в том, что (как кажется) ввод пользователя и пароля не принимается контроллером беспроводной локальной сети, когда он передается как команда - это единственный способ, которым SSH.NET может передать любой ввод AFAIK. Таким образом, с этой очень специальной реализацией интерактивного входа пользователя я не смог успешно войти в систему с помощью SSH.NET.   -  person Ryan Hardy    schedule 12.11.2017
comment
Так что задавайте вопрос о своей проблеме с SSH.NET, а не об обходном пути с Plink.   -  person Martin Prikryl    schedule 12.11.2017


Ответы (1)


Для кого это может быть полезно: я снова решил это с помощью SSH.NET, но на этот раз не используя встроенные функции для входа в систему, а используя в сочетании с ShellStream ручную обработку ввода и вывода. Работает отлично до сих пор.

person Ryan Hardy    schedule 26.11.2017