Запуск Wscript.Shell и Shell.Application. Заметки

10.08.21

Разработка - БСП (Библиотека стандартных подсистем)

Некоторые примечания по работе с запуском приложений.

Общих обзоров и материалов на эту тему уже достаточно, данная заметка не претендует на полноценную публикацию или исследование нюансов. Рассматривается только ОС Windows и только с точки зрения разработчика 1С, без подробностей системного администрирования и погружения в API винды. Переход по навигационным ссылкам (открытие страниц, запуск программ по протоколам) и открытие/запуск приложений по ассоциированным файлам не рассматриваем.

В общем случае разработчику доступны два командных процессора, cmd или powershell. Это именно исполнители команд, передающие далее ядру ОС более низкоуровневые команды; они доступны из консолей, пункта меню "Выполнить", они лежат в основе многих действий графических оболочек и системных менеджеров. 

При этом, cmd не имеет "надстройки", и обращение к ней это всегда консольная команда. А вот powershell предоставляет оболочку над утилитой, что упрощает некоторые действия, но создаёт путаницу между собственно процессором и его "управляющим" объектом в памяти некоего процесса. Причём, эта оболочка позволяет вызвать выполнение cmd. Сложно сказать, в каких терминологических отношениях, например, находятся API-функции и процессоры, поэтому фиксируем лишь практически важные, прикладные моменты.

Важно не путать, что мы запускаем (какой процессор) и чем запускаем (какая оболочка). Под оболочкой рассматриваем СОМ-объект, созданный динамически в ходе исполнения кода на языке 1С, безотносительно, на сервере 1С это или на клиенте.

Для запуска разработчику доступны две оболочки, WScript.Shell и Shell.Application. Суть одинакова: создаётся их объект, ведётся работа с его методами и свойствами, а суть - в исполнении командной строки, команды, обычно с параметрами. В общем случае командой может быть директива ОС, собственно команда, запуск пакетного файла (скрипта), запуск исполняемого файла, открытие файла по ассоциации ОС итд. В общем случае всё это можно звать запускаемым сценарием.

Запуск может ждать завершения, т.е. остановить процесс-инициатор до момента окончания/прерывания/вылета запущенного процесса, либо продолжить процесс-инициатор и взаимодействовать с запущенным в реальном времени. Называть ли это асинхронностью или многопоточностью - не столь важно, но с помощью взаимодействия нескольких запущенных процессов и их "родителя" можно добиться параллельности некоторых действий. Правильнее вообще говорить не столько об ожидании завершения, сколько об управляемости запущенного.

В обоих случаях запущенный что-то получает на вход, что-то отдаёт на выход (и как код возврата, и, если предусмотрел разработчик, как подробные выходные данные), что-то сообщает при ошибке. Всё это - общеизвестные потоки StdIn, StdOut, StdErr. Разумеется, не считая собственных фишек запускаемой команды, например, чтения из где-то лежащих файлов, записи в реестр итд. Поток можно читать поэтапно, целиком, направлять в переменную или файл, и всё это доступно либо на уровне файловых команд, либо через свойства и методы оболочек. Можно напрямую прописывать вывод результатов исполнения в файл (> и >>, т.е. полная перезапись и дописывание соответственно), учитывая доступ к местоположению такого файла.

 

WScript.Shell

Каждый экземпляр объекта WScript автоматически создаётся сервером сценариев (CScript.exe или WScript.exe) в момент вызова конструктора. Регистрация в СОМ+ и DCOM не требуется.

Создание: 
Оболочка = Новый COMОбъект("WScript.Shell"); // во времена 8.2 это не всегда работало, требовалось "подружить" 1С и WSH

 
 О свойствах оболочки

В некоторых случаях в передаваемой командной строке надёжнее писать путь вызова в формате 8х3, т.е. "C:\Progra~1\" итд.

По завершении работы с Оболочка её надо принудительно приравнять Неопределено. Если объект был создан на управляемой форме, то, за исключением общеизвестного "удержания", контекст и занимаемая память по закрытии формы будут сброшены, а вот если создан из общего модуля, и сложился ещё ряд факторов, то может остаться в памяти, в т.ч. по завершении создавшего сеанса.

Оболочка, в свою очередь, позволяет создавать процессы ОС, как объекты типа WshScriptExec (некоторые источники утверждают, что может потребоваться доступ ко всем зарегистрированным классам, на практике не сталкивался).

Опять же, можно запускать консольно: cscript.exe ПутьВКавычкахКФайлуСценария (запуск сценариев пакетно). Такой подход позволяет указать, какой сервер сценариев применять (CScript.exe или используемый по умолчанию WScript.exe), можно подавить вывод диалогов и сообщений сценария.


С возможностью управления

Запуск с порождением отдельного дочернего управляемого процесса, без ожидания завершения.

Процесс = Оболочка.Exec(СтрокаЗапуска);

 
 О свойствах процесса


Входной, выходной, ошибочный потоки: StdIn, StdOut, StdErr - это тоже свойства, возвращающие актуальные на момент обращения к ним потоки, они имеют тип объект "TextStream", соответствующий стандартному потоку. Доступны, если скрипт запущен с помощью CScript.exe.
ВходнойПоток = Оболочка.StdIn.ReadLine() или ReadAll(), или Read(КолвоСимволов).
Выходной поток StdOut и поток ошибок StdErr аналогично.

Примечания по потокам:
* Некоторые приложения пишут вывод прямо в консоль, а не в стандартный поток, поэтому читать его, а равно и перенаправлять куда-то, бесполезно.
* Ввод и вывод буферизуются, поэтому важно не забывать про свойство Поток.AtEndOfStream; например, известны случаи, когда из StdOut читается сразу всё-всё, или просто больше, чем буферизовано, то процесс 1С может тихо рухнуть (наблюдалось на 8.3.18.1289), а если читается строка, после которой программа ожидает ввод текста, то управление в запустивший процесс 1С никогда не вернётся и 1С повиснет. Особенно это касается фоновых заданий - при неаккуратной работе с потоками очень глючат.

 

Процесс, запущенный Exec, разумно мониторить в цикле с задержкой, и при необходимости насильственно прерывать. Для этого используют:

* Процесс.Terminate(); // показал себя как наиболее надёжный, но, если процесс уже завершился (например, рухнул по ошибке), вызов этого метода тоже вызовет ошибку; метод позволяет завершить дочерний процесс. Процессу будет послана команда WM_CLOSE, если это не сработает, то процесс будет завершен принудительно;

* Процесс.Quit(КодВозвратаКакОшибки) - необязательный числовой код возврата приложения // код возврата будет не в потоке выхода и не в потоке ошибок, а именно в ExitCode; метод поддерживается не всеми серверами.

Важно учитывать, что на 64-х битном сервере 1С (Именно 1С, не ОС) вспомогательный объект, например, "Процесс", не создается согласно политикам безопасности. Не все 32-х битные COM-ы могут быть вызваны 64-х битным приложением - например, MSScriptControl не может. И вообще приложение может быть скомпилировать в несовместимой разрядности, и сервер сценариев не сможет создать экземпляр объекта процесса такого приложения.

Метод позволяет контролировать ход работы запущенного процесса, и запущенный сценарий является дочерним для запускающего, ему присущи те же переменные среды Windows, что и у процесса-родителя, и те же ограничения доступа. Использование метода разумно для консольных приложений, которые выполняются в консольном окне, особенно с диалогами запросов пользователю. Видимость диалога определяется запуском на клиенте 1С и совокупностью свойств сервера сценариев. Метод работает более адекватно и прозрачно при возможных ограничениях UAC.

Концепция: запустили и управляем сами: можем подождать (Sleep), можем сразу опросить, можем прервать из 1С.


Без возможности управления

Запуск внешних приложений с ожиданием завершения.

КодВозврата = Оболочка.Run(СтрокаЗапуска, СостояниеОкна, ЖдатьЗавершения);

* СтрокаЗапуска - строка сценария; если содержит пробелы, то обязательно заключать её в двойные кавычки, иначе выдаст "The system cannot find the file specified", и настоятельно рекомендуется использовать переменные окружения в пути к приложению. Для Exec подобные требования менее часты и менее жёстки.
* СостояниеОкна - число (интересно разве что на клиенте), и обобщая VBScript, они таковы: 0 – скрывает окно, будет виден только процесс в диспетчере задач. 1 – нормальный режим 2 – свернутый вид 3 – развернутый вид;
* ЖдатьЗавершения - булево, остановить процесс-инициатор или продолжать. Если установлено Истина, то метод вернет числовой код возврата вызванного приложения, если установлено Ложь – всегда будет возвращаться ноль.

Никаких свойств или объектов не предусмотрено.

Метод работает строго аналогично команде ОС Windows "Пуск/Выполнить", и при запуске приложения сперва идет его поиск в переменных среды, поэтому имена наиболее употребительных приложений можно указывать без пути. Метод не позволяет контролировать ход работы запущенного процесса, и дочерним для запускающего запущенный сценарий не является, а идёт как независимый. При наличии неочевидных UAC работа метода превращается в чёрный ящик.

Диалоги могут быть видны, но "живут своей жизнью", а разумнее всего применять метод к приложениям, не выводящим никакие диалоги. Замечено, что в некоторых скриптах своеобразно игнорирует "@echo off", выводя пустое окно консоли на пару секунд.

Концепция: запустили и ждём, пока сама ОС не разберётся и не вернёт управление 1С.
 

Shell.Application

Как оболочка, по сути это программно-скриптовый способ обращения к объекту, представляющему диспетчер запускаемых задач, в графическом интерфейсе - банальный Windows Explorer (проводник). Работа с такой оболочкой тесно связана с возможностями и доступностью технологии OLE/COM-АctiveX, и вообще в значительной степени это просто Automation-сервер. Более чувствительна к свойствам объекта приложения, с которым имеет дело. Задействуются системные файлы проводника и Shell32.dll (чьи версии очень разные в зависимости от сборок; так, например, большинство современных возможностей пошли с PowerShell 4.0 от Win 8.1, и даже в MSDN открыто пишут, что не все объекты, свойства и методы гарантированно работают на все версиях Windows, а в качестве средства победить баг в первую очередь советуют ставить обновления для... MSIE. Вообще PowerShell как оболочка - способ менее прозрачный, менее управляемый, более зависимый от контекста среды, но имеет ряд достоинств.

Технически, shell-команды могут транслироваться в имена для ActiveX-элементов, например, описанных как ShellFolder в реестре (так, "shell:Downloads" это папка загрузок текущего юзера). Если АctiveX не имеет имени (а оно есть не всегда), можно обратиться по CLSID (так, "shell:::{3080F90D-D7AD-11D9-BD98-0000947B0257}" - это команда свернуть все окна).
С точки зрения разрешений и прав доступа, поведение PowerShell определяется и управляется, по умолчанию, профилем пользователя, под которым выполнялся запуск. Соответственно, на сервере 1С это пользователь ОС, под которым запущена служба (например, USR1CV8). Пользователи ИБ и БД, напомню, описаны на ИТС, обсуждались тут: https://forum.infostart.ru/forum9/topic224824/

Для запуска команд применяют метод ShellExecute и его расширенный вариант, начиная с Vista, ShellExecuteEx. Оба метода позволяют чётко разделить исполняемую команду и параметры к ней (не на уровне положения в командной строке или сценарии, а на этапе вызова). При вызове этих команд вызывается СОМ-консольно основная утилита-процессор: powershell <АргументыИПрочее>, т.е. по сути аналог start-process, а уж что ей передано, определяет разработчик. Повторюсь, это может быть команда, директива, имя файла скрипта; всё это с указанием командного процессора и, главное, с возможностью обойтись без ввода пароля и подтверждения UAC, что особенно ценно при исполнении на сервере, да ещё в фоновом задании. Можно применять напрямую процессор cmd, так, "powershell -Command" идёт применительно к нему.

Создание:

Оболочка = Новый COMОбъект("Shell.Application"); // если проблема с совместимостью, разрядностью или правами, то уже это действие завершится ошибкой

По завершении работы с Оболочка её желательно принудительно приравнять Неопределено, но по завершении сеанса/процесса-инициатора, т.е. 1С, также будет удалена. Кто знает примеры с зависанием и тем более утечкой памяти - пожалуйста, поделитесь.

 

ShellExecute

КодВозврата = Оболочка.ShellExecute(КомандныйПроцессор, АргументыДляДействия, КаталогВыполнения, ДействиеГлагол, СостояниеОкна); // все параметры, кроме первого, необязательны

* КомандныйПроцессор - например, "cmd";

* АргументыДляДействия - описание сценария, например, "/c """ + ИмяФайлаИлиКоманда + """";

* КаталогВыполнения - по умолчанию используется текущий каталог того сервера и того процесса, который инициирует запуск;

* ДействиеГлагол - см.ниже.

* Состояние окна интересно только на клиенте, это рекомендуемое состояние окна при выполнении, многие приложения это игнорируют, нотация аналогична вышеприведённой по vbs);

Результат метода, т.е. КодВозврата - именно возвращаемое запущенным процессом значение, а не какой-либо из связанных с ним потоков.

Метод позволяет использовать "действия", "глаголы" (Verbs), детализирующие выполняемое действие. Есть глаголы, применимые лишь к конкретным приложениям и не во всех случаях: "edit" (запуск редактора), "find" (поиск файла), "print" (печать файла), "properties" (получение свойств файла). Глагол по умолчанию - open. Для разработчика 1С представляет интерес глагол "Open" - запуск приложения, а если это не исполняемый файл, то ассоциированного с ним.

В большинстве документаций нет глагола, определяющего запуск от имени администратора, однако он есть и называется "runas", и тут есть нюансы. Отсутствие запроса подтверждения UAC не эквивалентно эскалации привилегий текущего пользователя, под которым выполняется запуск, или привилегий конкретного процесса - обычно речь идёт о запуске этим процессом другого, уже с административными полномочиями и наследованием переменных контекста.

Для этого в рамках командной строки применяется ключ "-verb runas" (регистр букв не важен), а в рассматриваемом методе, например, ShellExecute("cmd", "/c """ + Команда + """", , "runas", 0);

Такой запуск имеет свои особенности: вместе с "-Verb RunAs" нельзя использовать вывод в файл через -RedirectStandardError и -RedirectStandardOutput, нельзя указывать -Wait и -NoNewWindow.
Пример запуска самой оболочки из-под себя с повышением прав: powershell "start-process powershell -verb runas".

Надеюсь, очевидно, что PowerShell RunAs небезопасна, т.к. SaveCred добавляет удостоверение администратора и пароль в кэш учетных данных, и этот кэш, в принципе, можно перехватить. При этом, в ряде случаев поведение Windows Credential Manager может не удовлетворять требованиям безопасности, и тогда никакое повышение не сработает, и далеко не всегда это ловится кодом возврата, возможно, придётся смотреть журнал событий винды. За возможность запуска программ от имени другого пользователя в Windows отвечает служба вторичного входа в систему (Secondary Log-on). Если эта служба остановлена, все описанные методы с RunAs работать не будут (проверить, запущена ли служба, можно командой PowerShell вида "Get-Service seclogon").

 
 Другие способы, связанные с RunAs
 
 Примечания

 

Общие моменты

* Всегда учитывать, что VBScript разрешает пропускать необязательные параметры методов, а JScript нет! Особенно при заимствовании кода и копи-пасте с примеров в сети)))

* Ключевое значение имеет кодировка - и путей, передаваемых как параметры, и команд, и строк в скриптах, и потоков. Есть кодировка, указанная напрямую в файле скрипта (chcp), и есть, в которой записан файл скрипта и читаются файлы потоков, их нельзя путать и следует проверять/настраивать отдельно. Не стоит уповать на 1С-ный Юникод или системные настройки по умолчанию. Кавычку, например, для верности лучше задавать напрямую как Символ(34).

* Следует быть аккуратнее с расшаренными ресурсами, и с теми, запись в которые виртуализируется. У виртуальных дисков в консольных запусках порой запаздывает отклик ОС по доступу, в т.ч.отказ.

* Если прав по UAC недостаточно, то при запуске на клиенте может вылезти consent.exe с диалогом запроса подтверждения, а на сервере просто втихую не запустится. До потоков вывода и ошибок. До каких-то объектных действий. В таких случаях команду лучше обёртывать запускаемым файлом-скриптом (как делает БСП), а на сервере только смотреть журнал ОС насчёт ошибок, смотреть настройки безопасности IE (при нужде добавлять server-ivc в доверенную зону, с которой разрешён запуск исполняемых).

* Создание сом-объекта, естественно, оборачиваем в попытку-исключение и, естественно, нам доступно только позднее связывание, т.к. такие вещи как Active-Х и тем более OLE статично в объекты 1С не впихнуть. И не забываем про деструктор и уборку мусора за собой.

* Если надо содержимое консольного окна успеть посмотреть, а оно закрывается, используем (например, последней командой в скрипте) команду PAUSE, но тогда помним про особенности чтения потока вывода.

 

По мнению "1С"

На ИТС сравнительно мало конкретики, посвящённой особенностям работы СОМ-объектов с оболочками ОС, и она разрозненна.

Процитирую наиболее полезное: "При запуске внешней программы из кода требуется составлять строку запуска таким образом, чтобы она собиралась только из проверенных частей. если одна из частей, из которых собирается строка запуска, содержит данные, полученные из базы данных, из поля ввода на форме или прочитаны из хранилища настроек, то перед запуском программы требуется проверить, являются ли запуск безопасным. Безопасными считаются такие строковые данные, которые не содержат в себе следующие символы: "$", "`", "|", "||" ";", "&", "&&". Данное требование распространяется на все способы запуска программ."

С одной стороны, выглядит разумно; с другой - наличие в списке символа ";" делает небезопасным, например, запуск другой 1С по строке соединения /IBConnectionString, "благодаря" чему воспользоваться БСП для таких действий затруднительно.

 
 Как сделано в БСП

 

P.S. Всё вышеизложенное - так или иначе - баян и повтор. После блестящей статьи Ю.Пермитина вообще мало смысла освещать эту тему. Поэтому - просто заметка, скорее даже для себя. Аккордеон-антисклерозник.

P.P.S. Тухлые помидоры приветствуются, но, по возможности, конструктивные.

Wscript.Shell Shell.Application запуск внешних приложений из системные команды

См. также

БСП (Библиотека стандартных подсистем) Программист Платные (руб)

Синтакс-помощник БСП - cправочник по библиотекам стандартных подсистем и электронных документов. В состав справочника входит описание экспортных процедур и функций, размещенных в областях кода ПрограммныйИнтерфейс БСП и БЭД.

1800 руб.

21.11.2024    3647    16    15    

18

БСП (Библиотека стандартных подсистем) Программист Платформа 1С v8.3 Бесплатно (free)

Расскажу, как использовать полезный функционал - инструментарий разработчика «1С:Библиотека стандартных подсистем» (БСП) в своих объектах метаданных. Статья будет полезна как шпаргалка при написании собственных объектов метаданных.

27.12.2024    3446    PROSTO-1C    15    

43

БСП (Библиотека стандартных подсистем) Программист Бесплатно (free)

Синтакс-помощник БСП - справочник по Библиотеке Стандартных Подсистем, профессиональный инструмент разработчика с интуитивно понятным интерфейсом. Читайте в статье как использовать все возможности справочника и сделать работу с БСП более комфортной и эффективной.

11.12.2024    3906    gorenski    0    

8

БСП (Библиотека стандартных подсистем) Менеджеры внешних отчетов Программист Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление холдингом Абонемент ($m)

За последние лет 5 несколько раз сталкиваюсь с проблемой на разных проектах (в конфигурациях 1С:ERP, 1С:ERP УХ и многих других, основанных на БСП), когда много пользователей (около 30 тысяч) в информационной базе, время добавления доступа для пользователей занимает значительное время. Открытие списка занимает от 10 до 15 секунд, и каждое изменение списка еще примерно столько же.

1 стартмани

10.12.2024    997    Iaskeliainen    2    

7

БСП (Библиотека стандартных подсистем) Программист Платформа 1С v8.3 Бесплатно (free)

Некоторые нюансы, если вы захотите создавать свои расширения. Доработка отчета "Связанные документы" для отражения документов расширения. Печатные формы с шаблоном Word.

20.11.2024    3342    milkers    3    

12

БСП (Библиотека стандартных подсистем) Программист Платформа 1С v8.3 Бесплатно (free)

В статье описан алгоритм для включения документа или справочника в систему БСП. Будет полезно программистам 1С, начинающим работать с БСП.

24.10.2024    1684    PROSTO-1C    0    

18

БСП (Библиотека стандартных подсистем) Работа с интерфейсом Программист Платформа 1С v8.3 Бесплатно (free)

В материале описан универсальный механизм работы с добавленными элементами на общую форму «ФормаОтчета». Думаю, облегчит работу многим разработчикам.

08.10.2024    1374    PROSTO-1C    4    

14
Оставьте свое сообщение