Ограничение числа процессов толстого клиента 1С для пользователя Windows: Python, psutil и подмена ярлыка 1cestart

07.10.26

База данных - Администрирование СУБД

Покажем, как на рабочей станции ограничить одновременные процессы 1cv8c и 1cv8s для учётной записи Windows: промежуточный скрипт на Python с psutil, персональные лимиты и ярлык вместо прямого вызова 1cestart.exe. Инструкция без правок конфигураций и с учётом обходов и сеансов на сервере.

Ограничение числа одновременных процессов 1С для пользователей Windows сводится к подсчёту экземпляров 1cv8c.exe и 1cv8s.exe и к вызову штатного 1cestart.exe только пока лимит не исчерпан. Дальше разберём установку Python, счётчик через psutil и подмену цели ярлыка запуска толстого клиента 1С:Предприятие 8.3.

 

Когда одного пользователя и пятнадцати баз становится слишком много

На терминальном сервере или в офисе, где десятки информационных баз, картина повторяется: один сотрудник держит открытыми несколько клиентов сразу, иногда до пятнадцати окон. Каждый экземпляр толстого клиента забирает память на рабочем месте и добавляет нагрузку на сервер 1С и СУБД. Отклик сервера проседает, в консоли кластера виден всплеск одновременных сеансов и соединений, страдают те, кто работает в одной-двух базах.

Штатный ярлык «1C:Enterprise» или «1С:Предприятие» ведёт напрямую на 1cestart.exe. В этом ярлыке нет проверки числа процессов 1cv8c для текущей учётной записи Windows. Лимиты кластера, лицензирование и параметры безопасности процессы на рабочем ПК не считают.

Мы ограничиваем запуск на рабочей станции: перед каждым открытием из корпоративного ярлыка скрипт смотрит, сколько процессов толстого клиента и стартера уже принадлежит текущему пользователю, и только при соблюдении лимита вызывает привычное окно выбора базы через 1cestart.exe. Конфигурации 1С, расширения и регламентные задания на сервере не трогаем.

Под «процессами 1С» здесь имеются в виду 1cv8c.exe (работающий клиент) и 1cv8s.exe (окно стартера). «Ограничение в разрезе пользователей Windows» означает учётную запись, из-под которой запущен ярлык; чужие процессы на том же компьютере в лимит не входят. Тонкий клиент 1cv8.exe и веб-клиент в эту схему не входят.

Лимит на ярлыке срабатывает в момент попытки открыть ещё одно окно, то есть раньше, чем администратор успевает заметить пик нагрузки только по сеансам на сервере.

 

Схема решения: ярлык, проверка, 1cestart.exe

Ярлык для пользователя тот же по смыслу, но в свойствах вместо 1cestart.exe указан Limit1CStart.exe (или скрипт Python до сборки). Windows сначала запускает прослойку, та по полному пути вызывает 1cestart.exe. Выбор базы и параметры запуска остаются внутри стартера.

Скрипт отрабатывает только в момент вызова из ярлыка, поэтому стартер ограничивают отдельно. Если разрешить бесконечно открывать 1cv8s.exe, пользователь заранее поднимет несколько окон выбора базы и из каждого запустит клиент, обойдя проверку по 1cv8c. Правило «не более одного процесса 1cv8s.exe» закрывает эту лазейку в модели «контроль при каждом клике по ярлыку».

На 64-bit Windows 1cestart.exe чаще лежит в каталоге common установки платформы, например C:\Program Files (x86)\1cv8\common\1cestart.exe или C:\Program Files\1cv8\common\1cestart.exe. Встречается и путь через bin конкретной сборки 8.3.xx.xxxx: у релизов номер в каталоге меняется. Я сверяю фактический путь в свойствах штатного ярлыка «1C:Enterprise»; при необходимости смотрю ветки Uninstall в HKLM или HKCU для записи «1C:Enterprise 8.x» и поле DisplayIcon, откуда виден каталог bin и далее common. В константе ICESTART_PATH в коде должна стоять одна строка с вашим реальным путём, а не чужой пример из статьи.

EXE в сетевой папке имеет смысл, когда на всех рабочих местах одна версия платформы и один путь к common; в остальных случаях проще локальная копия с конфигом в ProgramData.

Ярлык параметры базы не передаёт: он лишь стартует прослойку проверки. Все параметры запуска пользователь задаёт внутри 1cestart.

 

Логика подсчёта процессов через psutil

Библиотека psutil обходит список процессов с атрибутами name и username без подключения к WMI. В исходных публикациях ту же роль играет процедура OpenCount1C(Num); в листинге ниже она названа open_count_1c, смысл тот же. Num - максимальное число одновременных клиентов 1cv8c.exe для текущего пользователя.

Алгоритм такой. Создаём два списка для процессов текущей учётной записи. В цикле psutil.process_iter с атрибутами username и name для каждой записи смотрим name и владельца. Сначала отбрасываем пустое username: у чужих процессов psutil часто не показывает владельца (в терминах API это NULL), и одного этого фильтра мало. Затем сравниваем имя владельца с текущим USERNAME и при необходимости с DOMAIN\user - так в лимит попадают только процессы этой учётной записи, даже если ярлык запускали «от имени администратора» и владелец чужих сеансов иногда виден.

Если name равен 1cv8c.exe и владелец совпал, имя попадает в список клиентов. То же для 1cv8s.exe - в список стартеров. CountList1cv8c и CountList1cv8s - длины списков. Запуск 1cestart разрешён, когда стартеров ещё нет и CountList1cv8c меньше Num; иначе показываем MessageBox с текстом от администратора, пишем строку в deny.log и завершаем процесс. Если 1cv8s уже один или больше, показываем отдельное сообщение про окно стартера, при желании фиксируем отказ в deny.log и выходим без нового 1cv8s.

Лимит «N баз одновременно» - это N процессов 1cv8c.exe. Попытка открыть клиент номер N плюс один блокируется, пока пользователь сам не закроет один из работающих экземпляров.

import ctypes
import json
import os
import sys
from datetime import datetime
from pathlib import Path

try:
    import psutil
except ImportError:
    ctypes.windll.user32.MessageBoxW(
        0,
        "Не установлен модуль psutil. Обратитесь к администратору.",
        "Ошибка запуска 1С",
        16,
    )
    sys.exit(1)

ICESTART_PATH = r"C:\Program Files (x86)\1cv8\common\1cestart.exe"
CONFIG_DIR = Path(os.environ.get("ProgramData", r"C:\ProgramData")) / "Limit1C"
CONFIG_PATH = CONFIG_DIR / "limits_1c.json"
LOG_PATH = CONFIG_DIR / "deny.log"

def load_limits():
    default = {"default": 4, "users": {}, "exclude": []}
    if CONFIG_PATH.is_file():
        with CONFIG_PATH.open(encoding="utf-8") as fh:
            data = json.load(fh)
            default.update(data)
    return default

def _username_variants():
    short = os.environ.get("USERNAME", "")
    domain = os.environ.get("USERDOMAIN", "")
    variants = set()
    if short:
        variants.add(short.upper())
        if domain:
            variants.add(f"{domain}\\{short}".upper())
    return variants

def _process_belongs_to_me(proc_username):
    if not proc_username:
        return False
    proc = proc_username.upper()
    if proc in _username_variants():
        return True
    short = os.environ.get("USERNAME", "")
    if short and proc.split("\\")[-1] == short.upper():
        return True
    return False

def log_deny(username, count_c, limit, reason="1cv8c_limit"):
    try:
        LOG_PATH.parent.mkdir(parents=True, exist_ok=True)
        with LOG_PATH.open("a", encoding="utf-8") as fh:
            fh.write(
                f"{datetime.now().isoformat(timespec='seconds')}"
                f"\t{username}\t{reason}\t1cv8c={count_c}\tlimit={limit}\n"
            )
    except OSError:
        pass

def open_1cestart():
    if not os.path.isfile(ICESTART_PATH):
        ctypes.windll.user32.MessageBoxW(
            0,
            f"Не найден 1cestart.exe:\n{ICESTART_PATH}",
            "Ошибка конфигурации",
            16,
        )
        sys.exit(1)
    os.startfile(ICESTART_PATH)

def open_count_1c(num):
    list_1cv8c = []
    list_1cv8s = []
    try:
        for proc in psutil.process_iter(attrs=["username", "name"]):
            info = proc.info
            if not _process_belongs_to_me(info.get("username")):
                continue
            name = info.get("name")
            if name == "1cv8c.exe":
                list_1cv8c.append(name)
            elif name == "1cv8s.exe":
                list_1cv8s.append(name)
    except (psutil.AccessDenied, psutil.NoSuchProcess):
        ctypes.windll.user32.MessageBoxW(
            0,
            "Нет прав на просмотр списка процессов. Запуск без проверки отменён.",
            "Ошибка",
            16,
        )
        sys.exit(1)

    count_1cv8c = len(list_1cv8c)
    count_1cv8s = len(list_1cv8s)
    username = os.environ.get("USERNAME", "")

    if count_1cv8s >= 1:
        log_deny(username, count_1cv8c, num, reason="1cv8s_already_running")
        ctypes.windll.user32.MessageBoxW(
            0,
            "Уже открыто окно стартера 1С. Закройте лишнее окно выбора базы.",
            "Уведомление",
            48,
        )
        sys.exit(0)

    if count_1cv8c < num:
        open_1cestart()
    else:
        log_deny(username, count_1cv8c, num)
        message = (
            "Администратором запрещено запускать более "
            + str(num)
            + " процессов 1С одновременно. Закройте лишнее окно клиента."
        )
        ctypes.windll.user32.MessageBoxW(0, message, "Уведомление о блокировке", 48)
        sys.exit(0)

def main():
    cfg = load_limits()
    username = os.environ.get("USERNAME", "")
    if username in cfg.get("exclude", []):
        open_1cestart()
        return
    limit = cfg.get("users", {}).get(username, cfg.get("default", 4))
    open_count_1c(int(limit))

if __name__ == "__main__":
    main()

Пример limits_1c.json в каталоге Limit1C под ProgramData (или рядом со скриптом на этапе отладки) заменяет длинные ветки elif по USERNAME:

{
  "default": 4,
  "exclude": ["Sobstvennik"],
  "users": {
    "Buhgalter1": 8,
    "Buhgalter2": 12
  }
}

Имена учётных записей в JSON должны совпадать с тем, что возвращает os.environ['USERNAME'] (часто латиница без домена). Для доменных профилей иногда удобнее сверять полное DOMAIN\user - в коде это учтено при сравнении владельца процесса.

На загруженном сервере или на сервере терминалов (Remote Desktop) с сотнями фоновых процессов пауза после двойного щелчка по ярлыку заметна. В типовых сравнениях из публикаций про такие скрипты обход через psutil обычно быстрее, чем через WMI: порядка десяти секунд против порядка тридцати восьми при около тысяче процессов. Это не обязательно ваш замер на площадке; если пользователи жалуются на задержку перед стартером, один раз сравните psutil и WMI у себя и зафиксируйте в регламенте.

 

Лимиты по пользователям и исключения

Персональные лимиты нужны, когда у бухгалтерии по регламенту открыто больше баз, чем у кладовщика, а у владельца или главного администратора счётчик вообще не должен срабатывать. В исходной схеме это ветки if USERNAME равен… с вызовом OpenCount1C(8) или прямым os.startfile для исключения.

Минус хардкода в коде: каждая смена состава требует правки скрипта и пересборки EXE. Файл limits_1c.json в каталоге, доступном администратору, позволяет менять цифры без компилятора. Конфиг отдают через групповые политики; пользователям выдают собранный EXE без исходников.

Исключение «без лимита» лучше явно перечислять в exclude. Исключения документируйте в конфиге и в регламенте, чтобы через полгода было ясно, почему у одной учётной записи снова много клиентов. Успешные запуски для exclude в deny.log не пишутся - только отказы по лимиту и по стартеру.

Дефолт для всех остальных, например четыре базы, задаётся одной строкой в конфиге. Новый сотрудник попадает под дефолт, пока администратор не добавит его в users. В main() после load_limits() проверяют exclude, затем берут limit из users.get(USERNAME, умолчанию) и передают в open_count_1c(limit).

 

Подготовка окружения: Python, pip, psutil

На Windows 10 и 11 я ставлю Python 3.10 или новее с python.org или через winget, с галочкой «Add python.exe to PATH». Лаунчер py вызывает интерпретатор без путаницы, когда установлено несколько версий: py -3 --version.

У свежего инсталлятора с python.org pip часто уже есть; если нет, скачивают официальный get-pip.py, открывают cmd в каталоге с файлом и выполняют py get-pip.py. Зависимость одной командой: py -m pip install --upgrade pip psutil.

На админском ПК для изоляции можно создать venv: py -m venv C:\Tools\limit1c-venv, активировать C:\Tools\limit1c-venv\Scripts\activate.bat, установить psutil внутри и гонять скрипт до сборки. На пользовательских машинах venv не нужен, если разворачиваем только EXE.

pip иногда попадает не в тот интерпретатор, и собранный EXE «не видит» psutil. Проверка сразу после установки: py -m pip show psutil.

Обычному пользователю хватает прав на чтение списка процессов. На ужесточённых политиках возможен AccessDenied для части записей; тогда в коде лучше не пускать в 1С молча, а показать сообщение, иначе создаётся ложное ощущение контроля.

 

Сборка EXE и настройка ярлыка

Пользователям проще ярлык на EXE, чем на.py и отдельный Python. Для админов удобнее auto-py-to-exe (py -m pip install auto-py-to-exe, затем py -m auto_py_to_exe); в CI или скриптах развёртывания - PyInstaller одной командой.

Пример onefile через PyInstaller после установки py -m pip install pyinstaller:

py -m PyInstaller --onefile --noconsole --name Limit1CStart limit_1c_start.py

Флаг --noconsole убирает мигающее чёрное окно при двойном щелчке. Файл limits_1c.json и deny.log для onefile кладут в C:\ProgramData\Limit1C\ (как в листинге CONFIG_PATH), а не рядом с временной распаковкой EXE, иначе после первого запуска конфиг «пропадёт». Установщик или GPO создаёт каталог и кладёт JSON.

Копируем существующий ярлык 1С, переименовываем, например «1С (лимит)». В свойствах в поле «Объект» указываем полный путь к Limit1CStart.exe. «Рабочая папка» может совпадать с каталогом EXE; конфиг читается из ProgramData. Иконку можно оставить от платформы, указав путь к 1cv8.exe или стандартному ico из bin.

Проверка вручную: при нуле клиентов ярлык открывает стартер. Из стартера поднимаем базы до лимита N. Следующий клик по ярлыку при N активных 1cv8c должен показать MessageBox и не открыть второй стартер, если 1cv8s уже есть. Закрыли один клиент - запуск снова разрешён. Два быстрых двойных щелчка подряд по ярлыку не должны оставить два 1cv8s (между обходом процессов и os.startfile теоретически возможна гонка; на тестовом ПК это стоит щёлкнуть дважды нарочно).

Через GPO кладут ярлык в общее меню «Пуск», старые ярлыки на прямой 1cestart убирают или перекрывают политикой запрета ярлыков на рабочем столе с прямым путём к bin. Иначе часть пользователей останется на обходе.

На тестовом ПК можно сравнить число процессов 1cv8c в диспетчере задач: с прямым ярлыком окна набираются без потолка, со скриптом-проверкой упираются в N.

 

Ограничения подхода и сочетание с администрированием 1С

Модель «только при запуске из ярлыка» обходят. Прямой запуск 1cestart.exe или 1cv8.exe из каталога bin, второй ярлык, автозапуск в профиле, копия exe на сетевом диске, ярлык из установщика платформы после очередного релиза 8.3 - всё это минует скрипт. Меры: один утверждённый ярлык, политики на рабочий стол, регламент, при необходимости AppLocker или WDAC на запуск 1cestart только из разрешённого каталога (отдельный проект по ИБ).

На сервере терминалов (Remote Desktop) лимит считается внутри сессии пользователя, где крутится скрипт. Два пользователя на одном хосте друг другу не мешают. Один пользователь с двумя сессиями, если политика это разрешает, получит два независимых счётчика - редкий, но возможный двойной лимит.

На сервере 1С процесс на ПК пользователя не тождественен одному сеансу кластера: один клиент - одно соединение, но зависшие сеансы, фоновые задания и внешние соединения через COM (V83.COMConnector) смотрим отдельно. Список сеансов и блокировки смотрите в консоли администрирования кластера и через rac/rac.exe к host:port агента кластера с учётными данными администратора кластера. Скрипт режет лишние окна толстого клиента на ПК; сеансы на сервере контролируются отдельно.

Ограничение процессов не подменяет лимиты сеансов и лицензий платформы: это локальный барьер от множества процессов клиента на рабочей станции, а не способ уменьшить число клиентских лицензий и перестать следить за кластером. Имеет смысл держать и лимит на ПК, и просмотр сеансов раз в смену по регламенту «один пользователь - N баз».

Тонкий и веб-клиент эту прослойку не затрагивают; при смешанном ландшафте лимит дублируют политиками там, где люди реально работают.

Перед раскаткой на группу рабочих мест проверьте три вещи: после смены версии платформы 8.3 путь ICESTART_PATH совпадает с фактическим 1cestart.exe; limits_1c.json читается из ProgramData; при искусственном превышении лимита появляется MessageBox и строка в deny.log. Если MessageBox не появляется, а клиенты множатся, первым делом смотрите диспетчер задач: путь к образу 1cv8c.exe покажет, стартовали ли в обход ярлыка.

Вступайте в нашу телеграмм-группу Инфостарт

1С:Предприятие 8.3 Администрирование Windows Python Толстый клиент Производительность psutil ограничение процессов 1С 1cv8c 1cv8s 1cestart Python Windows лимит баз на пользователя толстый клиент 1С

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

HighLoad оптимизация Администрирование СУБД Разработчик 1С:Предприятие 8 1С:ERP Управление предприятием 2 Бухгалтерский учет Бесплатно (free)

После миграции с MS SQL на PostgreSQL закрытие месяца в 1С:ERP стало идти 8 часов вместо 12 минут. Рассказываем, как мы нашли причину в оценке Hash Join, которую планировщик завышал в миллионы раз, и как исправили её так, что проблемный запрос теперь выполняется за 18 секунд вместо часа.

19.10.2026    971    Tantor    0    

10

Администрирование СУБД HighLoad оптимизация Разработчик 1С:Предприятие 8 1С:ERP Управление предприятием 2 Россия Бесплатно (free)

Большинство материалов о компрессии в PostgreSQL отвечают на вопрос «во сколько раз удалось уменьшить базу». Мы предлагаем посмотреть на проблему с другой стороны — какой ценой достигается эта экономия? В статье разбираем архитектурные компромиссы различных подходов к компрессии страниц, объясняем, почему при разработке CSM в Tantor Postgres отказались от погони за максимальным коэффициентом сжатия, и показываем результаты нагрузочных испытаний на реальных базах 1С.

01.10.2026    1472    Tantor    6    

17

DevOps и автоматизация разработки Администрирование СУБД Групповая разработка (Git, хранилище) Разработчик 1С 8.3 Абонемент ($m)

В корпоративных инсталляциях «1С:Предприятие 8.3» под управлением PostgreSQL всё чаще проявляются архитектурные пределы масштабирования: рост числа пользователей, обязательная маркировка, плотный поток API-интеграций и высокая стоимость простоя. Вводная часть цикла разбирает ключевые факторы современной эксплуатационной нагрузки и формирует инженерную методологию эволюционной модернизации без остановки продуктивного контура. Материал основан на практическом кейсе «Торговый контур» и показывает, как определить целевые метрики (p95, MTTR, APDEX), выстроить наблюдаемость, стабилизировать работу кластера и подготовить инфраструктуру к дальнейшему масштабированию. Публикация задаёт фундамент для последующих частей, посвящённых телеметрии, оптимизации PostgreSQL, CI/CD и архитектурному росту.

1 стартмани

10.09.2026    1540    Ninel_S    0    

6

HighLoad оптимизация Администрирование СУБД Разработчик 1С:Предприятие 8 1С:ERP Управление предприятием 2 Бесплатно (free)

В рамках 18 релиза СУБД Tantor Postgres мы рассказывали об оптимизациях, которые помогают планировщику сделать более точный выбор между Nested Loop и Hash Join. В следующем релизе у нас планируются оптимизации, которые позволят ускорить выполнение как Nested Loop, так и Hash Join. Сегодня мы расскажем об одном из таких методов - фильтре Блума.

31.08.2026    6141    Tantor    3    

18

Администрирование СУБД Системный администратор Разработчик 1С 8.3 Бесплатно (free)

Мы подготовили для сообщества Infostart.ru практическое занятие, в котором каждый желающий сможет: научиться собирать реальные данные о процессах кластера 1С; выявлять «перестарков» — процессы старше периода и без соединений; выполнять безопасный перезапуск (с dry-run и подтверждением); настраивать автоматическую проверку через systemd на Linux; отправлять уведомления (Telegram, почта) при обнаружении проблем; работать с логами, ротацией, профилями кластеров и конфигурацией; развернуть полноценный учебный проект AdminClusterMonitor у себя в тестовой среде.

30.08.2026    1753    Ninel_S    2    

6

Администрирование СУБД Системный администратор 1С:Предприятие 8 Бесплатно (free)

На infostart.ru вышел разбор Ивана Недомолкова «Сервер 1С падает: настройка сбора дампов (logcfg.xml), лимиты памяти и передача дампа в поддержку» - это хорошая инструкция, как ловить и разбирать падение rphost постфактум: logcfg.xml, procdump, анализ дампа. Но там нет ответа на вопрос «а почему кластер вообще прибил процесс сам, ещё до всякого краша». Мы дополняем разбор тремя сводными таблицами лимитов памяти и автомасштабирования кластера - и заодно фиксируем, чем в этой части лицензия ПРОФ урезана относительно КОРП.

12.08.2026    2418    Ninel_S    5    

6

Администрирование СУБД Системный администратор Разработчик Бесплатно (free)

5,5 тысячи пользователей в единой базе 1С, розница в режиме 24/7 и SLA 99,98% – в таких условиях любая авария быстро превращается в очереди на кассах, потерю денег и давление со стороны бизнеса. Показываем, как выстроить процесс аварийно-восстановительных работ: от первых алертов и базового скрининга системы до подключения команды, проверки гипотез и дебрифа после инцидента. Разбираем, как метрики, дашборды, техжурнал, Zabbix, Prometheus, Grafana, Telegram-боты и скрипты помогают не гадать, а быстро находить причину проблемы. На реальных авариях объясняем, почему «быстро» не должно означать «рискованно», как работа над ошибками снижает панику и почему каждая авария может сделать систему надежнее.

11.08.2026    3427    jul.dolganova    9    

24
Для отправки сообщения требуется регистрация/авторизация