using System; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Text; namespace SshStatusUpdater { internal class Program { // ================= НАСТРОЙКИ ПОДКЛЮЧЕНИЯ ================= private const string RemoteUser = "depfile"; // Логин пользователя на сервере private const string RemoteHost = "10.228.48.110"; // IP-адрес или DNS-имя сервера private const int RemotePort = 22; // Порт SSH-сервера // Путь к приватному ключу по умолчанию (если не задан аргументом) private const string DefaultKeyPath = @"D:\sys\C-Sharp\deployfile\key\test_key.key"; // ======================================================== static int Main(string[] args) { // 1. Определение пути к ключу string rawKeyPath = (args.Length > 0 && !string.IsNullOrWhiteSpace(args[0])) ? args[0].Trim('"') : DefaultKeyPath; string keyPath = Environment.ExpandEnvironmentVariables(rawKeyPath); if (!File.Exists(keyPath)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"Ошибка: Файл ключа не найден по указанному пути: {keyPath}"); Console.ResetColor(); return 2; } Console.WriteLine($"Используется ключ: {keyPath}"); // 2. Проверка доступности OpenSSH клиента (с возможностью автоустановки) string sshExecutable = EnsureOpenSshAvailable(); if (string.IsNullOrEmpty(sshExecutable)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("\n[ОШИБКА] Клиент OpenSSH не найден в системе и не удалось выполнить его установку."); Console.WriteLine("Для работы приложения необходимо установить компонент OpenSSH вручную."); Console.WriteLine("Откройте PowerShell от имени Администратора и выполните:"); Console.WriteLine(" Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0"); Console.ResetColor(); return 4; } // 3. Формирование полезной нагрузки и удаленной команды string randomContent = GenerateRandomPayload(linesCount: 5, charsPerLine: 32); // Относительные пути от домашнего каталога /var/lib/depfile string remoteCommand = "mkdir -p status && cat > status/change.me && (cd status && sha256sum change.me > sha256.hash)"; string sshArgs = $"-i \"{keyPath}\" -p {RemotePort} -o BatchMode=yes -o StrictHostKeyChecking=accept-new {RemoteUser}@{RemoteHost} \"{remoteCommand}\""; ProcessStartInfo psi = new ProcessStartInfo { FileName = sshExecutable, Arguments = sshArgs, UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true }; Console.WriteLine($"Подключение к {RemoteUser}@{RemoteHost}:{RemotePort}..."); try { using (Process proc = new Process { StartInfo = psi }) { proc.Start(); // Передаем сгенерированный текст в STDIN удаленного процесса ssh using (StreamWriter sw = new StreamWriter(proc.StandardInput.BaseStream, new UTF8Encoding(false))) { sw.Write(randomContent); } string stdOut = proc.StandardOutput.ReadToEnd(); string stdErr = proc.StandardError.ReadToEnd(); proc.WaitForExit(); if (proc.ExitCode == 0) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Файл status/change.me и хеш status/sha256.hash успешно созданы на сервере."); Console.ResetColor(); return 0; } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"Ошибка выполнения SSH (Код: {proc.ExitCode}):"); if (!string.IsNullOrWhiteSpace(stdErr)) Console.WriteLine(stdErr.Trim()); if (!string.IsNullOrWhiteSpace(stdOut)) Console.WriteLine(stdOut.Trim()); Console.ResetColor(); return proc.ExitCode; } } } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"Критическая ошибка выполнения SSH: {ex.Message}"); Console.ResetColor(); return 3; } } private static string EnsureOpenSshAvailable() { string path = FindSshPath(); if (!string.IsNullOrEmpty(path)) return path; Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("Клиент OpenSSH не обнаружен. Попытка автоматической установки компонента Windows..."); Console.ResetColor(); bool installed = TryInstallOpenSsh(); if (installed) { path = FindSshPath(); if (!string.IsNullOrEmpty(path)) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Клиент OpenSSH успешно установлен."); Console.ResetColor(); return path; } } return null; } private static string FindSshPath() { string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows); string[] candidates = new[] { Path.Combine(windir, "Sysnative", "OpenSSH", "ssh.exe"), Path.Combine(windir, "System32", "OpenSSH", "ssh.exe"), @"C:\Windows\System32\OpenSSH\ssh.exe" }; foreach (var candidate in candidates) { if (File.Exists(candidate)) return candidate; } try { ProcessStartInfo testPsi = new ProcessStartInfo { FileName = "ssh", Arguments = "-V", UseShellExecute = false, RedirectStandardError = true, RedirectStandardOutput = true, CreateNoWindow = true }; using (var testProc = Process.Start(testPsi)) { testProc?.WaitForExit(1000); return "ssh"; } } catch { } return null; } private static string TryInstallOpenSsh() { try { ProcessStartInfo installPsi = new ProcessStartInfo { FileName = "powershell.exe", Arguments = "-NoProfile -ExecutionPolicy Bypass -Command \"Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0\"", UseShellExecute = true, Verb = "runas", WindowStyle = ProcessWindowStyle.Normal }; using (Process installProc = Process.Start(installPsi)) { if (installProc == null) return false; installProc.WaitForExit(); return installProc.ExitCode == 0; } } catch (Win32Exception) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("Запрос прав Администратора был отклонён пользователем."); Console.ResetColor(); return false; } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"Не удалось запустить автоматическую установку: {ex.Message}"); Console.ResetColor(); return false; } } private static string GenerateRandomPayload(int linesCount, int charsPerLine) { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; StringBuilder sb = new StringBuilder(); Random rng = new Random(); for (int i = 0; i < linesCount; i++) { char[] buffer = new char[charsPerLine]; for (int j = 0; j < charsPerLine; j++) { buffer[j] = chars[rng.Next(chars.Length)]; } sb.AppendLine(new string(buffer)); } return sb.ToString(); } } }