Принудительное завершение сеансов 1С из скрипта, кода и по расписанию
Содержание
Закрыть сеанс 1С программно в клиент-серверной базе можно тремя путями: утилитой rac через сервер администрирования (RAS), объектом V83.COMConnector из кода 1С или PowerShell, либо мягко — блокировкой входа с ожиданием, пока пользователи выйдут сами. Для разовой задачи удобнее rac, для кнопки внутри конфигурации — COM, для ночного регламента — PowerShell-скрипт в планировщике.
В файловой базе кластера нет, поэтому ни rac, ни COM-агент не помогут: там работают только блокировка сеансов и закрытие процессов 1cv8.exe на рабочих местах. Ниже — команды и код для платформы 8.3 с сервером на Windows Server 2016 и новее; для Linux меняются только пути.
Какой способ завершения сеансов выбрать
| Способ | Где выполняется | Когда подходит | Что нужно |
|---|---|---|---|
rac + RAS | на сервере 1С или админской машине | разово, из bat/PowerShell, на Linux | запущенный ras, пароль администратора кластера |
V83.COMConnector | в серверном коде 1С или скрипте Windows | кнопка «выгнать всех» в обработке, старые скрипты | зарегистрированный comcntr.dll нужной разрядности |
| Блокировка сеансов | в самой базе | перед обновлением: предупредить и не пускать новых | права администратора в базе |
| Закрытие процессов | на рабочем месте или терминальном сервере | файловая база, зависший клиент | права администратора ОС |
💡 Связь между способами простая: номер сеанса, который видит код 1С (НомерСеанса), равен полю session-id в выводе rac и свойству SessionID в COM. По нему удобно искать один и тот же сеанс в разных инструментах.
Закрытый сеанс теряет несохранённые данные. Открытая форма документа, незаписанный отчёт, незавершённая транзакция откатываются. Принудительное закрытие делайте вне рабочего времени или после предупреждения пользователей.
Завершение сеансов из встроенного языка 1С
Что умеет код без доступа к кластеру
Сам по себе код конфигурации видит сеансы, но чужой сеанс не закрывает — для этого нужен вход в кластер. Получить список можно так:
&НаСервере
Процедура ПоказатьСеансы()
Для Каждого Сеанс Из ПолучитьСеансыИнформационнойБазы() Цикл
Сообщить(СтрШаблон("%1 | %2 | %3 | %4",
Формат(Сеанс.НомерСеанса, "ЧГ=0"),
Сеанс.Пользователь,
Сеанс.ИмяПриложения,
Сеанс.ИмяКомпьютера));
КонецЦикла;
КонецПроцедуры
Свой сеанс завершает метод ЗавершитьРаботуСистемы() на клиенте. Чужой — только через кластер.
Блокировка входа: мягкий вариант
Блокировка не выгоняет тех, кто уже работает, а закрывает дверь для новых. Пользователи с параметром запуска /UC<код> проходят, остальные видят ваше сообщение.
&НаСервере
Процедура ЗаблокироватьВход()
Блокировка = Новый БлокировкаСеансов;
Блокировка.Установлена = Истина;
Блокировка.Начало = ТекущаяДатаСеанса();
Блокировка.Конец = ТекущаяДатаСеанса() + 3600;
Блокировка.КодРазрешения = "admin-upd";
Блокировка.Сообщение = "Идёт обновление базы, вход откроется в течение часа";
УстановитьБлокировкуСеансов(Блокировка);
КонецПроцедуры
В типовых конфигурациях на БСП то же самое делается без кода: Администрирование → Обслуживание, ссылка «Блокировка работы пользователей». Там блокировка ещё и предупреждает работающих пользователей и через заданное время закрывает их клиенты.
Завершение чужих сеансов из кода через COM
Код ниже выполняется на сервере 1С под учётной записью службы, поэтому comcntr.dll должен быть зарегистрирован на сервере. Он закрывает все сеансы указанного пользователя в указанной базе и не трогает текущий сеанс.
&НаСервереБезКонтекста
Функция ЗавершитьСеансыПользователя(ИмяБазы, ИмяПользователя, АдминКластера, ПарольКластера)
Коннектор = Новый COMОбъект("V83.COMConnector");
Агент = Коннектор.ConnectAgent("tcp://srv1c:1540");
Кластер = Неопределено;
Для Каждого Элемент Из Агент.GetClusters() Цикл
Кластер = Элемент;
Прервать;
КонецЦикла;
Агент.Authenticate(Кластер, АдминКластера, ПарольКластера);
НомерТекущего = ПолучитьТекущийСеансИнформационнойБазы().НомерСеанса;
Закрыто = 0;
Для Каждого Сеанс Из Агент.GetSessions(Кластер) Цикл
Если НРег(Сеанс.infoBase.Name) <> НРег(ИмяБазы) Тогда
Продолжить;
КонецЕсли;
Если Сеанс.UserName <> ИмяПользователя Или Сеанс.SessionID = НомерТекущего Тогда
Продолжить;
КонецЕсли;
Агент.TerminateSession(Кластер, Сеанс);
Закрыто = Закрыто + 1;
КонецЦикла;
Возврат Закрыто;
КонецФункции
💡 Пароль администратора кластера не храните в тексте модуля. В конфигурациях на БСП для этого есть безопасное хранилище данных, в своей разработке — хотя бы константа с ограниченными правами.
Закрыть сеанс 1С через rac: кластер, база, конкретный ID
Запуск сервера администрирования
rac общается не с агентом напрямую, а с сервером администрирования ras. По умолчанию он слушает порт 1545. Для пробы его запускают вручную:
cd "C:\Program Files\1cv8\8.3.25.1394\bin"
ras.exe cluster --port=1545 localhost:1540
Для постоянной работы ras регистрируют службой Windows через sc create — иначе после перезагрузки сервера скрипты перестанут работать. Номер версии в пути замените на свой.
Поиск кластера, базы и сеансов
rac cluster list
rac infobase summary list --cluster=<uuid-кластера> --cluster-user=admin --cluster-pwd=***
rac session list --cluster=<uuid-кластера> --infobase=<uuid-базы> --cluster-user=admin --cluster-pwd=***
Первая команда даёт поле cluster — это UUID. Вторая показывает базы: поле infobase (UUID) и name. Третья выводит сеансы базы блоками «ключ : значение». Нужные поля:
- 🔑
session— UUID, его передают в команду завершения; - 🔢
session-id— короткий номер, как в консоли и в коде 1С; - 👤
user-name— пользователь базы; - 🖥️
host— компьютер; - 📱
app-id— тип клиента:1CV8C(тонкий),1CV8(толстый),WebClient,Designer,COMConnection,BackgroundJob; - 🕐
started-at,last-active-at— начало и последняя активность.
Завершение сеанса по ID
rac session terminate --cluster=<uuid-кластера> --session=<uuid-сеанса> --cluster-user=admin --cluster-pwd=***
Команда принимает именно UUID из поля session, а не номер session-id. Если знаете только номер (например, из «Активных пользователей»), найдите его в выводе session list и возьмите UUID из того же блока.
Завершение всех сеансов пользователя
Отдельной команды «закрыть всё у пользователя» нет: фильтруете список и завершаете в цикле. В PowerShell это три строки (функция разбора вывода — в разделе про автоматизацию):
ConvertFrom-Rac (& $rac session list @auth "--infobase=$ibId") |
Where-Object { $_.'user-name' -eq 'Петрова' } |
ForEach-Object { & $rac session terminate @auth "--session=$($_.session)" }
Чтобы заодно закрыть вход новым пользователям, у rac infobase update есть параметры блокировки сеансов (--sessions-deny, --denied-message, --permission-code). Для них нужен ещё логин и пароль пользователя базы; полный список — в rac help infobase.
Внешнее управление через V83.COMConnector
Тот же объект, что используется в коде 1С, доступен любому языку Windows с поддержкой COM. Это вариант для тех, у кого не запущен ras, но есть доступ к агенту на порт 1540.
Регистрация компоненты (из командной строки администратора):
regsvr32 "C:\Program Files\1cv8\8.3.25.1394\bin\comcntr.dll"
Разрядность важна: 64-битный PowerShell видит только 64-битную comcntr.dll, 32-битный — только 32-битную. Ошибка «класс не зарегистрирован» почти всегда означает несовпадение разрядности или версии.
$conn = New-Object -ComObject V83.COMConnector
$agent = $conn.ConnectAgent("tcp://srv1c:1540")
$cluster = $agent.GetClusters()[0]
$agent.Authenticate($cluster, "admin", $env:C1_ADMIN_PWD)
$agent.GetSessions($cluster) |
Where-Object { $_.infoBase.Name -eq "buh" -and $_.AppID -ne "BackgroundJob" } |
ForEach-Object { $agent.TerminateSession($cluster, $_) }
Минус COM — привязка к версии платформы. После обновления 1С компоненту нужно перерегистрировать из каталога новой версии, иначе скрипт либо падает, либо подключается старым коннектором и получает отказ.
Автоматизация: PowerShell и планировщик задач
Типичная задача — в 02:30 закрыть все пользовательские сеансы перед резервной копией или регламентом. Скрипт на rac надёжнее COM: не зависит от регистрации DLL.
# C:\scripts\close-1c.ps1
$rac = "C:\Program Files\1cv8\8.3.25.1394\bin\rac.exe"
$base = "buh"
$log = "C:\scripts\logs\close-1c_{0:yyyyMMdd}.log" -f (Get-Date)
function ConvertFrom-Rac([string[]]$Lines) {
$obj = [ordered]@{}
foreach ($l in $Lines + '') {
if ($l -match '^\s*$') {
if ($obj.Count) { [pscustomobject]$obj; $obj = [ordered]@{} }
} elseif ($l -match '^([\w-]+)\s*:\s*(.*)$') {
$obj[$Matches[1]] = $Matches[2].Trim().Trim('"')
}
}
}
$clusterId = (ConvertFrom-Rac (& $rac cluster list))[0].cluster
$auth = @("--cluster=$clusterId", "--cluster-user=admin", "--cluster-pwd=$env:C1_ADMIN_PWD")
$ib = ConvertFrom-Rac (& $rac infobase summary list @auth) | Where-Object { $_.name -eq $base }
$skip = @('BackgroundJob', 'SrvrConsole')
foreach ($s in ConvertFrom-Rac (& $rac session list @auth "--infobase=$($ib.infobase)")) {
if ($s.'app-id' -in $skip) { continue }
& $rac session terminate @auth "--session=$($s.session)"
Add-Content $log ("{0:HH:mm:ss} закрыт #{1} {2} {3} {4}" -f (Get-Date), $s.'session-id', $s.'user-name', $s.'app-id', $s.host)
}
Регистрация задачи (командная строка от администратора):
schtasks /Create /TN "1C\Закрыть сеансы" /SC DAILY /ST 02:30 /RU SYSTEM ^
/TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\scripts\close-1c.ps1"
Пароль C1_ADMIN_PWD задайте системной переменной среды, а не строкой в скрипте. На Linux логика та же: rac лежит в /opt/1cv8/x86_64/<версия>/, задача ставится в cron, разбор вывода делают через awk.
💡 Если имена пользователей в выводе rac приходят нечитаемыми символами (кодировка консоли), фильтруйте по UUID базы и app-id, а не по user-name.
Файловая база, веб-клиент и мобильные подключения
Файловая база. Кластера нет, поэтому есть два инструмента. Первый — блокировка сеансов (код выше или типовая обработка): БСП-конфигурации сами предупредят и закроют клиентов. Второй — завершение процессов на терминальном сервере, где работают пользователи:
taskkill /IM 1cv8c.exe /F
taskkill /IM 1cv8.exe /F
Это аварийная мера: процесс убивается без сохранения. Файл 1Cv8.1CL в каталоге базы руками не удаляйте — это служебный файл блокировок.
Веб-клиент. Сеанс веб-клиента живёт на сервере 1С и закрывается так же, как тонкий клиент — по UUID через rac или COM. У пользователя при следующем обращении к серверу появится сообщение о завершении сеанса. Закрытая вкладка браузера сеанс сразу не завершает: он может перейти в спящий режим. В выводе session list у таких сеансов видно поле hibernate.
Мобильные и HTTP-подключения. Мобильное приложение с автономной работой подключается к серверу на время обмена, через веб-сервисы или HTTP-сервисы. Такие сеансы видны с app-id вида WSConnection или HTTPServiceConnection и обычно короткие. Ночной скрипт их закроет, но при следующей синхронизации приложение просто подключится заново — на время регламента лучше включить блокировку сеансов.
Почему не через SQL и не через файлы кластера
У кластера 1С нет системной базы данных в SQL. Реестр кластера — это файлы в каталоге srvinfo на сервере, и редактировать их нельзя: испорченный реестр не даст кластеру стартовать.
Убить соединение рабочего процесса в СУБД (например, командой KILL в SQL Server) технически можно, но сеанс 1С от этого не завершится. Рабочий процесс получит ошибку посреди транзакции, а пользователь — сообщение об ошибке СУБД. Сеанс останется в кластере и будет занимать лицензию.
| Действие | Что произойдёт |
|---|---|
KILL соединения в SQL | ошибка у пользователя, сеанс 1С остаётся |
Перезапуск рабочего процесса rphost | обрываются все сеансы на нём, без разбора |
| Перезапуск службы агента | обрываются все сеансы всех баз кластера |
rac session terminate | закрыт ровно один сеанс, лицензия освобождена |
Перезапуск рабочего процесса или службы агента — крайняя мера, только в нерабочее время и после предупреждения пользователей: оборвутся сеансы во всех базах на этом сервере.
Как вести журнал завершённых сеансов
Журнал регистрации базы фиксирует событие «Сеанс. Завершение», но не говорит, кто закрыл сеанс: администратор, таймаут или сам пользователь. Поэтому свой след оставляйте явно.
- 📝 В скрипте — строка в текстовом журнале на каждый закрытый сеанс: время, номер, пользователь, тип клиента, компьютер (как в примере выше).
- 📝 В коде 1С — запись в журнал регистрации перед вызовом
TerminateSession:
ЗаписьЖурналаРегистрации("Администрирование.ЗавершениеСеанса",
УровеньЖурналаРегистрации.Предупреждение, , ,
СтрШаблон("Закрыт сеанс %1 пользователя %2 (%3)",
Формат(Сеанс.SessionID, "ЧГ=0"), Сеанс.UserName, Сеанс.AppID));
- 📝 Для разбора жалоб — отбор журнала регистрации по событию «Сеанс. Завершение» и пользователю. Если время совпадает с записью вашего скрипта, сеанс закрыл регламент.
Логи скрипта храните хотя бы месяц: вопросы «кто меня выкинул и почему пропал документ» приходят с задержкой.
Частые вопросы
Освобождается ли лицензия после завершения сеанса?
rac session list --licenses.Что увидит пользователь, если его сеанс закрыли?
Почему rac отвечает, что администратор кластера не аутентифицирован?
--cluster-user и --cluster-pwd или пароль неверный. Если администраторов нет, параметры не нужны.Можно ли закрыть зависшее фоновое задание через завершение сеанса?
app-id BackgroundJob. Но сначала попробуйте отменить задание штатно: из кода методом Отменить() у объекта фонового задания или из консоли кластера. Транзакция откатится в обоих случаях.Работает ли V83.COMConnector, если сервер 1С на Linux?
ras и rac, их можно вызывать и с Windows-машины администратора.