При интеграции 1С с системными утилитами операционной системы часто требуется не просто запустить внешнюю команду, но и получить результат её выполнения (например, статус выполнения утилиты ping, вывод утилит сетевой диагностики, архиваторов или консольных скриптов).
Штатная процедура 1С КомандаСистемы() запускает указанное приложение синхронно, однако она не возвращает результат работы команды и не позволяет напрямую перехватить текстовый поток вывода (stdout или stderr) в переменную. Разберем по шагам несколько надежных способов решения этой задачи.
Рассмотрим использование системного COM-объекта WScript.Shell и его метода Exec. Этот метод создает дочерний процесс и предоставляет прямой программный доступ к стандартным потокам ввода-вывода (StdIn, StdOut, StdErr).
Посмотрим на пример реализации с построчным чтением потока вывода:
WshShell = СоздатьОбъект("WScript.Shell");
WshExec = WshShell.Exec("ping 192.168.2.1");
TextStream = WshExec.StdOut;
Вывод = "";
Пока TextStream.AtEndOfStream = 0 Цикл
// Вычитываем строку из потока вывода
СтрокаВывода = TextStream.ReadLine();
Вывод = Вывод + СтрокаВывода + РазделительСтрок;
КонецЦикла;
Сообщить(Вывод);
Проанализируем важные технические нюансы этого метода:
Exec по своей архитектуре всегда открывает черное окно консоли во время работы дочернего процесса. Если требуется полностью скрытое фоновое выполнение, следует использовать метод Run с перенаправлением в файл.StdErr, процесс может приостановиться в ожидании освобождения буфера. При выполнении сложных команд рекомендуется последовательно проверять статус процесса WshExec.Status.Если появление черного окна консоли нежелательно для пользователя, разберем наиболее стабильный способ: запуск командного интерпретатора в скрытом режиме с перенаправлением потока (>) во временный текстовый файл с последующим чтением через объект Текст.
Посмотрим на пример программной реализации:
КаталогВременныхФайлов = КаталогВременныхФайлов();
ИмяФайла = КаталогВременныхФайлов + "cmd_output.txt";
WshShell = СоздатьОбъект("WScript.Shell");
// Запускаем командный интерпретатор %ComSpec% /c
// 0 - скрытый режим окна, 1 - ожидать завершения команды
Команда = "%ComSpec% /c ping 192.168.2.1 > """ + ИмяФайла + """";
КодВозврата = WshShell.Run(Команда, 0, 1);
ФайлВывода = СоздатьОбъект("Текст");
// Устанавливаем кодовую страницу OEM (DOS/CP866) для корректного чтения кириллицы
ФайлВывода.КодоваяСтраница(1);
Если ФС.СуществуетФайл(ИмяФайла) = 1 Тогда
ФайлВывода.Открыть(ИмяФайла);
Для НомерСтроки = 1 По ФайлВывода.КоличествоСтрок() Цикл
Сообщить(ФайлВывода.ПолучитьСтроку(НомерСтроки));
КонецЦикла;
// Закрываем и удаляем временный файл
ФайлВывода.Очистить();
ФС.УдалитьФайл(ИмяФайла);
Иначе
Сообщить("Не удалось получить результат выполнения команды.");
КонецЕсли;
В этом варианте метод КодоваяСтраница(1) объекта Текст автоматически преобразует символы из DOS-кодировки в привычный для 1С формат ANSI, исключая появление нечитаемых символов.
Если основной задачей вызова ping является проверка доступности определенного узла сети, более производительным и надежным решением будет использование системного интерфейса WMI (Windows Management Instrumentation).
Разберем пример запроса к WMI-классу Win32_PingStatus:
WbemLocator = СоздатьОбъект("WbemScripting.SWbemLocator");
WbemServices = WbemLocator.ConnectServer(".", "root\cimv2");
Узел = "192.168.2.1";
Запрос = "SELECT * FROM Win32_PingStatus WHERE Address = '" + Узел + "'";
Результаты = WbemServices.ExecQuery(Запрос);
Для Каждого Объекта Из Результаты Цикл
Если Объекта.StatusCode = 0 Тогда
Сообщить("Узел " + Узел + " доступен. Время ответа: " + Строка(Объекта.ResponseTime) + " мс");
Иначе
Сообщить("Узел " + Узел + " недоступен. Код ошибки: " + Строка(Объекта.StatusCode));
КонецЕсли;
КонецЦикла;
Преимущества работы через WMI: выполнение происходит полностью в фоновом режиме, не создает временных файлов на диске, не зависит от языка операционной системы и не требует последующего разбора текстовых строк.