Image

Category:

Проблема: запуск AutoIT программы в блокированном сеансе Windows

Удивительно, проработав несколько лет мой скрипт AutoIT для автоматизации сборки проекта из MG-SOFT Visual MIB Builder 9 в один день перестал работать и файлы перестали собираться. При активном рабочем столе однако все работало. Также и при подключении по удаленному доступу к рабочему столу — скрипты работают пока окно не свернуто и активно.

Предыстория

MG-SOFT Visual MIB Builder 9 у нас лицензионный потому мы его до сих пор используем для работы, но вот вручную экспортировать готовые MIB и вручную же их проверять это рутинно и скучно, особенно при наличии сервера автоматизации Jenkins.

Я пользуясь привилегией лени над палкой, написал на AutoIT 3 автоматизатор, который кликал куда надо за меня и на вывод кидал бы мне список ошибок, если они есть. Если сборка падает я сразу в письме получаю список ошибок в проекте по каждому файлу.

Чтобы Jenkins мог выполнять задачи в которых задействованы графические приложения я создал удаленный сборщик Jenkins (далее jenkins-gui-win-slave) на этой же машине. На ПК создан отдельный пользователь ci-server в сеансе которого при входе в систему запускается из автостарта скрипт запуска агента Jenkins. Подключается агент через Java WebStart, JNLP. Чтобы jenkins-gui-win-slave стартовал для пользователя ci-server настроен автоматический вход в систему при старте ПК, в автозапуске лежит скрипт запуска  jenkins-gui-win-slave, а в планировщике заданий Windows есть задача "при входе" выполнить "скрипт блокировки сеанса пользователя" — это позволяет сразу после входа заблокировать от нежелательных посетителей сервера сеанс ci-server.

В итоге при старте системы происходит автоматический вход для пользователя  `ci-server`, запуск агента  `jenkins-gui-win-slave`, блокирование сеанса пользователя  `ci-server`.

Проблема

Программы при блокировке сеанса Windows помещает приложения в изолированный сеанс Session 0 для обеспечения безопасности, т.к. считается, что активность в графическом приложении во время блокировки должна отсутствовать. Это накладывает ограничения, и часть оконных функций тогда не работает.

В отношении к AutoIT это приводит к тому, что невозможно дождаться события активации окна WinWaitActive, WinActive всегда возвращает ошибку, невозможно управлять мышью, невозможно переключить активное окно, потому и функции работающие в контексте активного окна перестают работать, например Send.

Решение

Есть два решения: без изменения кода и с изменением кода.

1. Без изменения кода

Установить виртуальную машину, в нее поставить Windows, агент Jenkins и нужное для сборки ПО. Причем для Windows 7 Pro можно использовать легально Windows XP Mode — получаете виртуалку с XP  и на ней все гоняете. Или используйте другое ПО для виртуализации, например VirtualBox, туда придется ставить ОС отдельно. Для виртуалки нужно настроить IP адрес, чтобы агент Jenkins мог подключаться к мастер серверу Jenkins. Для XP Mode IP адреса также можно настроить

В виртуалке можно использовать  пользователя по умолчанию.

В виртуалке в папку Автозапуск поместить скрипт командной строки (.bat\.cmd) для запуска агента Jenkins.

Пример скрипт запуска агента Jenkins:

rem Runs jenkins-gui-win-slave to work with GUI builds

SET http_proxy=

set https_proxy=

"C:\Program Files\Java\jre1.8.0_151\bin\java.exe" -jar "C:\Program Files\Jenkins\war\WEB-INF\slave.jar" -jnlpUrl http://<jenkins-master-addr>:8080/computer/jenkins-gui-win-slave/slave-agent.jnlp -secret <secret_string>

:: Где

:: jenkins-master-addr — адрес MASTER сервера jenkins

:: secret_string — ключ доступа к серверу для агента, см. в настройках агента на сервере Jenkins

Отключить скринсервер, отключить функцию "начитать с блокировки экрана". Настроить автоматический вход для пользователя без пароля при старте системы.

Далее настроить автозапуск виртуалки.

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

2. С изменением кода

Я пошел этим путем, т.к. у меня только одна такая задача была. 

Чтобы обойти ограничения режима блокировки, нужно:

  1. отказаться от тех функций, что работают с активными окнами или заменить их на альтернативные.
  2. Отказаться от движения мышью MouseMove, MouseClick и т.п.
  3. Заменять функцию Send на ControlSend или ControlClick.

Примечание: скрипты записанные Au3Record используют как раз функции не работающие в режиме блокировки сеанса.

С приложением работаем так будто бы окна уже активны в момент обращения.

Заменяем:

; Делаем окно активным и жмем кнопку
if (WinActivate($windowName)) Then
; Нажать кнопку в окне
ControlClick($windowName, $buttonName, "")
EndIf

На:

; Попытаемся сделать активным окно. При блокировке сеанса может не срабатывать, но нам и не важно
WinActivate($windowName)
; Нажимаем кнопку
ControlClick($windowName, $buttonName, "")
; или ControlSend($windowName, "", $buttonClass, "{SPACE}")

Лучше дожидаться появления окна через WinWait и после использовать полученный хендл окна для отправки ему сообщений.

В данном случае можно работать с существующей инфраструктурой на сервере, но не все скрипты могут быть так однозначно трансформировать. Некоторые приложения могут быть не приспособлены для такого взаимодействия, тогда придется прибегнуть к варианту 1.