После некоторых событий, на производстве появилась необходимость упрощения, удешевления и автоматизации входа постов (тонких клиентов) в 1С.

Какие основные моменты нужно было решить:

  1. Убрать хранение пароля в ветке реестра Winlogon на ОС Windows

  2. Убрать хранение пароля пользователя 1С в скрипте .bat в идеале настроить сквозную авторизацию в 1С

  3. Попробовать дать вторую жизнь устаревшим компьютерам с 1-2 гб ОЗУ и процессорами Intel Atom D425, или старее

  4. Автоматизировать вход до 1С сканированием единственного штрихкода на рабочем месте

  5. Минимизировать время замены рабочей станции в случае аварии/выхода из строя

  6. Сделать универсальный образ как для Legacy так и для UEFI совместимых компьютеров

Начну с того, что нигде полностью готового решения или хотя бы статьи-инструкции "сделай сам" я не нашёл

Также отмечу важный момент касаемо статьи, данная статья предназначена для начально-среднего уровня и для тех кто только начинает погружаться в IT, поэтому для многих нюансы и моменты самой статьи могут быть крайне очевидны и просты

Для удобства ориентирования в статье создано оглавление с переходами, с него и начнём:

Оглавление

  1. Установка Linux UEFI

  2. Настройка Linux UEFI

  3. Установка Linux Legacy

  4. Настройка Linux Legacy

  5. Настройка Windows Server

  6. Итоги

  1. Установка Linux UEFI x64

Как и в большинстве создаваемых образов мы начинаем с установки ОС, но так как нам нужен универсальный образ как для Legacy так и для UEFI совместимых систем, то обычным - далее - далее - готово не обойтись

Создаём виртуальную машину второго поколения и создаём диск на 25Гб и грузим ВМ в режиме UEFI, если использовать Hyper-V то дополнительных настроек ВМ не требуется, кроме отключения безопасного режима WIndows в параметрах:

отключение безопасного режима
отключение безопасного режима

После того как мы загрузились с Live CD образа Linux, в нашем случае это Linux Antix. Вы сможете использовать любой другой дистрибутив, чем легче тем лучше, так как в одном образе будет две ОС и два загрузчика Legacy и EFI.

Грузимся в режиме UEFI, и необходимо перейти к настройке разделов жёсткого диска.

При установке разбиваем диск на 4 раздела:

  1-й раздел fat32 - esp - 100 мб
  2-й раздел пустой - 500 мб (можно не делать, но лучше оставить)
  3-й раздел ext4 - 10Гб, размер достаточный для ОС antix UEFI, маркировка раздела "/"
  4-й раздел ext4 - 10Гб, размер достаточный для ОС antix Legacy, раздел без маркировки

В итоге у вас получится что-то подобное:

Разбиение диска (партиция)
Разбиение диска (партиция)

После нажатия на Next важно выставить загрузчик GRUB в формат ESP,

GRUB в формате ESP
GRUB в формате ESP

На следующем шагу задаём имя компьютера (можно оставить по умолчанию)
После чего выбираем свой регион и язык системы:

локаль
локаль

И на последнем шагу установки необходимо задать имя пользователя, пароль пользователя, и обязательно придумать новый пароль root-пользователя и для удобства поставить галочку Autologon

логин и пароль
логин и пароль

На этом часть установки UEFI завершена и предварительно образ подготовлен, поэтому переходим к начальной настройке образа:

2. Настройка Linux UEFI

Важный момент - настройка ОС для автоматического входа по штрихкоду производится единожды и аналогично по обеим версиям ОС, что для Legacy, что для UEFI

Первым пунктом настройки необходимо проверить наличие обновлений Linux, для этого выполняем команду:

sudo apt-get update -y && sudo apt-get upgrade -y

После успешного обновления будет доступно обновление ядра, чем мы и займёмся, выполнив команду:

sudo apt-cache search linux-image* amd64

Ищем новую версию ядра

В вашем случае количество версий ядра может быть много, рекомендую найти в интернете актуальную для вашей версии ОС
В нашем случае это linux-image-6.1.0-38-amd64, а значит завершим обновление ядра командой:

sudo apt-get install linux-image-6.1.0-38-amd64

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

ВАЖНО! для Legacy системы в нашем случае версия ядра будет linux-image-6.1.0-38-686-pae

После успешной перезагрузки производим подготовку образа для автоматизации и удобства, вводя команды по очереди:

sudo apt -y install freerdp2-x11 #ставим rdp клиент (можете использовать любой)
sudo apt -y install wmctrl #ставим ПО для того чтобы терминал был всегда поверх всех окон (необязателен, но будет использован в скрипте далее)
sudo apt -y install xfce4-terminal #ставим  терминал с возможностью установки логотипа компании, или любого другого изображения, если такой функционал необходим
sudo apt -y install systemctl #диспетчер служб, пригодится в будущем (в вашей ОС он может быть предустановлен, пропустите если это так)
sudo apt -y install ssh #клиент ssh, для простого управления и возможности создавать и передавать файлы (после завершения настройки также будет выключен)
ip a #узнаём IP-адрес ко��пьютера (нужно для подключения по ssh)

На этом предварительная и основная часть необходимого ПО для работы установлена. Теперь нам нужен любой компьютер на Windows (или ПО способное работать по ssh например KiTTY или PuTTY или аналоги)

Я же воспользуюсь стандартным powershell-ом windows, поскольку для настройки его достаточно
В командной строке powershell вводим команду:

ssh -p 22 test@192.168.72.136

где
-p - номер порта, если ничего не меняли, то по умолчанию порт 22
test - имя пользователя
@ - разделитель
192.168.72.136 - айпи адрес полученный командой ip a

После подключения ssh запросит сертификат и написав yes запросит пароль пользователя, в моём случае пароль пользователя test, подключившись вы увидите следующую картину:

ssh
ssh

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

Создаём файл:

nano rdp.sh #создание файла с расширением .sh (название файла может быть любым)

При создании файла откроется GNU nano 7.2, по факту это просто пустой текстовый файл. Заполним его скриптом:

Содержимое файла rdp.sh
#!/bin/bash
# Устанавливаем терминал всегда поверх всех окон (не обязательно)
wmctrl -r :ACTIVE: -b add,above
# Делаем скрипт цикличным (обязательно)
while :
do
# Текст для отображения
prompt="ОТСКАНИРУЙТЕ ШТРИХКОД АВТОРИЗАЦИИ НА ПОСТУ"
# Определяем ширину и высоту терминала
term_width=$(tput cols)
term_height=$(tput lines)
# Определяем длину строки с текстом
prompt_length=${#prompt}
# Вычисляем отступы для горизонтального центрирования текста
padding=$(( (term_width - prompt_length - 4) / 2 ))
# Создаем верхнюю и нижнюю границы
border=$(printf "%-${term_width}s" "" | tr " " "-")
# Задаем фиксированное количество пустых строк для вертикального отступа (70% от высоты терминала)
vertical_offset=$(( term_height * 70 / 100 ))
# Выводим пустые строки для вертикального смещения
for ((i=0; i<vertical_offset; i++)); do
echo ""
done
# Выводим табличку
echo "$border"
printf "%*s %s %*s\n" $padding "" "$prompt" $padding ""
echo "$border"
# Чтение ввода пользователя (скрытый ввод)
read -sp " " input
echo  # Печатаем новую строку после ввода
# Обработка введенных данных
server=$(echo -e $input | awk -F'@' '{print $1}')   # Всё до @
login=$(echo -e $input | awk -F'@' '{print $2}')    # Всё между @
password=$(echo -e $input | awk -F'@' '{print $3}') # Всё после @
# Выполнение команды freerdp с введенными данными (как раз вход по rdp)
xfreerdp /v:$server /u:$login /p:$password /cert:ignore /sec:nla /bpp:16 /f
clear  # Очистка экрана после выполнения команды
done

Коротко, что делает скрипт выше:

При его выполнении в терминале, окно скрипта (терминала) благодаря wmctrl становится поверх всех окон, затем скрипт создаёт цикл, чтобы в случае разрыва связи с сервером скрипт перезапустился и снова ждал ввода, после чего он определяет высоту и ширину окна терминала, чтобы текст "ОТСКАНИРУЙТЕ ШТРИХКОД АВТОРИЗАЦИИ НА ПОСТУ" был по центру, строкой vertical_offset=$(( term_height * 70 / 100 )) определяется высота где выводимый текст будет находиться, в нашем случае на 70% экрана (то есть ниже середины).
Далее выводится табличка из тире вокруг текста (для фокуса информативности)
Строка read -sp " " input скрывает набираемый пользователем текст (в нашем случае сканером)
В конце создаём три параметра @server, @login, @password
ВАЖНО! Знак @ является разделителем для штрихкода, то есть в пароле нельзя использовать этот символ
ВАЖНО! В штрихкоде вам нужно будет сгенерировать:
Имя-сервера@логин-пользователя@пароль-пользователя
И уже в конце стандартными командами freerdp подключаемся к серверу
Так как freerdp2 не умеет в сертификаты, пишем /cert:ignore, метод сетевого подключения /sec:nla
/bpp:16 - битность цвета, чем меньше тем быстрее работает на устаревшем железе, но и хуже передаваемая по rdp картинка
/f - полноэкранный режим
Более подробный синтаксис freerdp можно найти в интернете или командой xfreerdp --help в терминале
В конце, чтобы скрипт мог работать из автозапуска делаем его активным, введя команду:

sudo chmod +x rdp.sh #у вас название скрипта может отличаться

Основная часть настройки скрипта завершена, проверим его работу введя

./rdp.sh 
первое тестирование скрипта
первое тестирование скрипта

Как мы видим скрипт ждёт ввода команды.
Переходим к настройке автозапуска, для него пригодится приложение mc, ставим:

sudo apt-get install mc

Запустим mc:

sudo mc

Стрелками на клавиатуре идём по пути .icewm и находим там файл startup после чего жмём F4.
И добавляем в файл startup команды:

sleep 1 #нужен чтобы старые и слабые компьютеры не ломали положение окна терминала (можно увеличить время ожидания если это необходимо)
xfce4-terminal  -e /home/test/rdp.sh --fullscreen & #запуск xfce4 терминала со скриптом rdp.sh в полноэкранном режиме

Жмём сначала F2, чтобы сохранить изменение в файле, затем F10, чтобы его закрыть.
ВАЖНО! Обратите внимание, что операнд & ставится только в конце, поскольку сначала на старом ПК должна отработать пауза, иначе положение терминала может быть не во весь экран.
Теперь при перезагрузке компьютера автоматически запустится терминал xfce4, а уже в нём выполнится скрипт rdp.sh

Прежде чем продолжить, обязательно настроим загрузчик GRUB вписав в mc:

sudo nano /etc/default/grub

Откроется файл конфигурации загрузчика GRUB
Меняем значение GRUB_TIMEOUT=5 на GRUB_TIMEOUT=1
Данная настройка уменьшит время ожидания во время загрузки компьютера.
Важно! Чтобы применить изменения в GRUB нужно ввести команду:

sudo update-grub

Теперь скроем нижнюю панель рабочего стола. В mc идём по пути .icewm и открываем файл preference клавишей F4, нажимаем F7 и ищем ShowTaskBar=1, меняем его значение на 0, сохраняем с помощью F2 и закрываем на F10. У вас может быть другая ОС и не факт что там будет файл preference с настройкой рабочего стола

На этом основные настройки завершены, перезагружаем компь��тер и проверяем, что Linux запускает терминал со скриптом.

запуск скрипта из автозагрузки
запуск скрипта из автозагрузки

ВАЖНО! У вас данное окно будет выглядеть с полосой прокрутки справа и панелью настроек сверху. Жмём "Вид" и убираем галочку "Показывать строку меню"
Затем, единожды жмём ПКМ в любой точке терминала - настройки, во вкладке "Общие" убираем полосу прокрутки:

настройка xfce-терминала
настройка xfce-терминала

Во вкладке "Вид" вы сможете установить необходимое изображение или логотип организации (если необходимо)

Во вкладке "Дополнительно" нужно поставить галочки для отключения быстрых клавиш и отдельно галочку "Прятать курсор мыши"

прячем лишнее в терминале
прячем лишнее в терминале

После окончания настройки, выключаем виртуальную машину и создаём новую, первого поколения, которая будет работать в режиме Legacy, и подключаем к ней диск первой ВМ и установочный .iso образ того же самого Linux, в нашем случае Antix-а и грузимся с неё

3. Установка Linux Legacy

Установка Legacy Linux сводится к настройке разметки жестких дисков.
Не пересоздаём таблицу разделов на разделах которая была пустой в предыдущей установке, выставляем маркировку раздела "/". (для трех разделов она будет sda3, для четырех sda4). Продолжаем установку и устанавливаем загрузчик GRUB в режим MBR. Затем как в предыдущей установке создаём имя пользователя, пароль, пароль root и на этом установка второй системы завершена.

4. Настройка Linux Legacy

Настройка Linux Legacy x86 производится также как и Linux UEFI, с двумя отличиями:
1. Команда обновления ядра Linux:

sudo apt-get install linux-image-6.1.0-38-686-pae

2. Нужно снять бекап акронисом или иной любой системой, чтобы под рукой был универсальный образ. Из-за двух ОС на диске, при развёртывании образа на любом из ПК будь то Legacy или UEFI, компьютер автоматически найдёт нужный загрузчик и дойдёт до рабочего стола с запущенным скриптом rdp.sh
На этом настройка Linux составляющей завершена, переходим к настройке серверной части:

5. Установка Windows Server 2019

Установку Windows Server 2019 производите штатно, поскольку никаких дополнительных компонентов кроме службы удалённых рабочих столов нам не нужно.

После установки нам необходимо убрать (скрыть) рабочий стол от пользователя и настроить скрипт для автоматического входа в 1С, а также добавить его в автоматическую загрузку
Так как для разных пользователей могут открываться разные формы 1С, то и в скриптах это нужно указать

Начнём с удаления рабочего стола.

Жмём сочетание клавиш Win+R и вводим regedit, и идём по пути:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Winlogon находим в нём строковый парамет�� Shell и очищаем его:

скрытие рабочего стола
скрытие рабочего стола

После перезагрузки вместо привычного рабочего стола Windows пользователь увидит чёрный экран. Дальше создайте папку в Program Files (либо где угодно и где вам удобно, у нас действует политика запрета запуска ПО, поэтому пользователям разрешено запускать скрипты и программы только из Program Files/Program Files(x86).

Последним шагом останется создать скрипты с расширениями .cmd и .ps1, первый будет запускать второй, это нужно чтобы не менять ExecutionPolicy для запуска powershell скриптов, а строго указать их в .cmd для каждого отдельного скрипта.

Создаём файл shell.cmd (вы можете назвать его как угодно, главное расширение .cmd или .bat) со следующим содержимым:

@echo off
set SCRIPT="C:\Program Files\Post\test.ps1" #путь к файлу скрипта
start "" /min powershell.exe -NoProfile -ExecutionPolicy Bypass -File %SCRIPT%
exit /b

Скрипт отрабатывает единожды, запуская powershell.exe с ExecutionPolicy Bypass и файл test.ps1 в свёрнутом состоянии (можно сделать полностью скрытым).

Создаём файл test.ps1 с содержимым:

Содержимое файла test.ps1
# Настройки
$ExePath   = 'C:\Program Files (x86)\1cv8\common\1cestart.exe'  # путь до 1с
$Arguments = 'enterprise /Sname-server.local/name-base-1c' # или $null / '' если без аргументов
$CheckInterval = 2    # сек между проверками
$WindowWaitTimeout = 30 # сек ожидания появления окна после запуска

# Импорт WinAPI
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public static class Win32 {
    [DllImport("user32.dll")]
    public static extern bool SetForegroundWindow(IntPtr hWnd);
    [DllImport("user32.dll")]
    public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    [DllImport("user32.dll")]
    public static extern bool IsIconic(IntPtr hWnd);
    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();
    [DllImport("user32.dll")]
    public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
    [DllImport("kernel32.dll")]
    public static extern uint GetCurrentThreadId();
    [DllImport("user32.dll")]
    public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
    [DllImport("user32.dll")]
    public static extern bool BringWindowToTop(IntPtr hWnd);
}
"@ -Language CSharp

function Bring-WindowToFront {
    param([Parameter(Mandatory=$true)][IntPtr]$hWnd)

    if ($hWnd -eq [IntPtr]::Zero) { return $false }

    $SW_RESTORE = 9

    try {
        # Если свернуто — развернуть
        if ([Win32]::IsIconic($hWnd)) {
            [Win32]::ShowWindow($hWnd, $SW_RESTORE) | Out-Null
        }

        # Если уже на переднем плане — OK
        $fg = [Win32]::GetForegroundWindow()
        if ($fg -eq $hWnd) { return $true }

        # Попытка корректно переключить поток ввода между текущим передним окном и целевым окном
        $foregroundThread = [Win32]::GetWindowThreadProcessId($fg, [ref]0)
        $targetThread = [Win32]::GetWindowThreadProcessId($hWnd, [ref]0)

        if ($foregroundThread -ne $targetThread) {
            [Win32]::AttachThreadInput($foregroundThread, $targetThread, $true) | Out-Null
            [Win32]::SetForegroundWindow($hWnd) | Out-Null
            [Win32]::BringWindowToTop($hWnd) | Out-Null
            [Win32]::AttachThreadInput($foregroundThread, $targetThread, $false) | Out-Null
        } else {
            [Win32]::SetForegroundWindow($hWnd) | Out-Null
            [Win32]::BringWindowToTop($hWnd) | Out-Null
        }

        return $true
    } catch {
        Write-Host "$(Get-Date -Format 'HH:mm:ss') - Ошибка в Bring-WindowToFront: $($_.Exception.Message)"
        return $false
    }
}
# Текущая сессия (чтобы не пытаться управлять процессами других пользователей)
$mySession = (Get-Process -Id $PID).SessionId
Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Старт watcher. Проверка каждые $CheckInterval сек."

while ($true) {
    try {
        # Найти процессы 1cv8* в той же сессии
        $procs = Get-Process -Name '1cv8*' -ErrorAction SilentlyContinue | Where-Object { $_.SessionId -eq $mySession }

        if (-not $procs) {
            Write-Host "$(Get-Date -Format 'HH:mm:ss') - Процесс 1cv8 не найден. Запускаю $ExePath"
            try {
                if ([string]::IsNullOrEmpty($Arguments)) {
                    $started = Start-Process -FilePath $ExePath -WorkingDirectory (Split-Path $ExePath) -PassThru
                } else {                    $started = Start-Process -FilePath $ExePath -ArgumentList $Arguments -WorkingDirectory (Split-Path $ExePath) -PassThru
                }

                if ($started) {
                    Write-Host "$(Get-Date -Format 'HH:mm:ss') - Процесс запущен PID $($started.Id). Жду появления окна (макс. $WindowWaitTimeout сек)..."
# Ждём пока у процесса появится MainWindowHandle (в цикле, т.к. приложение может ещё инициализироваться)
                    $sw = [Diagnostics.Stopwatch]::StartNew()
                    while ($sw.Elapsed.TotalSeconds -lt $WindowWaitTimeout) {
                        try { $started.Refresh() } catch {}
                        if ($started.MainWindowHandle -ne 0) { break }
                        Start-Sleep -Milliseconds 500
                    }
                    if ($started.MainWindowHandle -ne 0) {
                        $hwnd = [IntPtr]$started.MainWindowHandle
                        if (Bring-WindowToFront -hWnd $hwnd) {
                            Write-Host "$(Get-Date -Format 'HH:mm:ss') - Окно только что запущенного процесса развернуто и выведено на передний план."
                        }
                    } else {
                        Write-Host "$(Get-Date -Format 'HH:mm:ss') - Окно процесса не появилось за $WindowWaitTimeout сек. Буду мониторить далее."
                    }
                } else {
                    Write-Host "$(Get-Date -Format 'HH:mm:ss') - Start-Process вернул null."
                }
            } catch {
                Write-Host "$(Get-Date -Format 'HH:mm:ss') - Ошибка при запуске: $($_.Exception.Message)"
            }
        } else {
            # Выбираем первый процесс с GUI-окном
            $withWindow = $procs | Where-Object { $_.MainWindowHandle -ne 0 } | Select-Object -First 1
            if ($withWindow) {
                $hwnd = [IntPtr]$withWindow.MainWindowHandle
                # Если окно свернуто — восстановить и вывести на передний план
                if ([Win32]::IsIconic($hwnd)) {
                    Write-Host "$(Get-Date -Format 'HH:mm:ss') - Процесс PID $($withWindow.Id) свернут. Восстанавливаю..."
                    if (Bring-WindowToFront -hWnd $hwnd) {
                        Write-Host "$(Get-Date -Format 'HH:mm:ss') - Окно восстановлено."
                    } else {
                        Write-Host "$(Get-Date -Format 'HH:mm:ss') - Не удалось привести окно на передний план."
                    }
                } else {
                    # при желании можно всегда пытаться поставить вперед (закомментируйте если не нужно)
                    # Bring-WindowToFront -hWnd $hwnd | Out-Null
                }
            } else {
                # Есть процессы, но у них ещё нет окна — подождём, возможно приложение инициализируется
                Write-Host "$(Get-Date -Format 'HH:mm:ss') - Процессы 1cv8 найдены, но GUI-окна пока нет. Ожидаю..."
            }
        }
    } catch {
        Write-Host "$(Get-Date -Format 'HH:mm:ss') - Ошибка в основном цикле: $($_.Exception.Message)"
    }
    Start-Sleep -Seconds $CheckInterval
}

Кратко что делает скрипт:

1. Запускает 1С.

2. Добавляет в запуск 1С аргументы: $Arguments = 'enterprise /Sname-server.local/name-base-1c', где S - имя сервера/имя базы, также в аргументы можно добавить какой клиент 1С или какие формы/параметры применить к 1С, пример: /RunModeOrdinaryApplication /CStartWorkPlaceSGP (более подробно аргументы легко находятся в интернете).

3. Запускает постоянный мониторинг процесса 1Сv8* в конкретной сессии пользователя, в случае если пользователь свернёт 1С (случайно или намеренно), то 1С развернётся скриптом автоматически, а также откроет 1С, если пользователь также случайно или намеренно закроет её.

На этом настройка скриптов завершена, теперь нам необходимо добавить исполняемый скрипт shell.cmd в автозагрузку Windows, так как мы ранее удалили рабочий стол, то просто закинуть ярлык скрипта в shell:startup не выйдет, также как и добавление его в AppData.
Поэтому добавим строковый параметр Shell для каждого пользователя в Winlogon, открываем редактор реестра и идём по пути:
HKEY_USERS\S-1-5-21-3492369290-2824618148-845011953-4159\Software\Microsoft\Windows NT\CurrentVersion\Winlogon и создаём строковый параметр Shell и добавляем в него путь до исполняемого скрипта:

добавление автозагрузки
добавление автозагрузки

ВАЖНО! Параметр S-1-5-21-3492369290-2824618148-845011953-* для каждого домена и пользователя генерируется случайно, поэтому, чтобы автоматизировать добавление автозапуска скриптов для пользователей необходимо создать групповую политику по автоматическому добавлению строкового параметра при первом входе пользователем на сервер. Данную групповую политику лучше нацелить на пользователей в определённой OU в AD

На этом полноценная настройка Windows Server 2019 завершена, при входе на сервер, отсканировав штрихкод авторизации, пользователь попадёт на сервер с автоматически запущенной 1С с аргументами указанными в скрипте

6. Итоги:

Изначальные вопросы автоматизации и упрощения входа пользователями решены, также как и максимальное ускорение восстановления рабочего места в случае выхода ПК из строя, поскольку образ универсален и не требует дополнительных настроек после развёртывания образа на любом ПК.

Что можно улучшить:

  1. Перехватить и запретить стандартные сочетание клавиш пользователем установив в Linux пакет по замене стандартных сочетаний клавиш, например Keyd.

  2. Внести образ установки и нужное ПО в ipxe (или аналоги) и разворачивать систему по сети, без необходимости носить с собой флешки.

  3. Оптимизировать сборку и превратить её в полноценный тонкий клиент, добавив все необходимые настройки и скрипты в развёртку ОС по сети, создав два отдельных образа весом 200+-Мб.

На этом настройка автоматизации входа по сканированию одного штрихкода завершена.