
Представьте: ваша организация закупила 100 новых компьютеров, на каждый из которых нужно установить десяток различных программ (текстовые редакторы, браузеры, средства коммуникации, разработки и тд.). Ручная установка займёт огромное количество времени, а ошибки и человеческий фактор удвоят затраченное время вдвое.
Но есть способ лучше - автоматизация через Chocolatey и PowerShell. В этой статье разберём:
Как развернуть ПО на всех машинах за кратчайший срок;
Как создать собственные пакеты и управлять ими;
Как внедрить данное решение в вашу организацию.
Если вы системный администратор, DevOps, ИТ-инженер или специалист ТП - постараюсь помочь сэкономить вам десятки часов рутинной работы.
Автоматизация установки ПО в корпоративной сети
Итак, основная проблема. Недавно моя организация закупила партию из 100 новых машин, которые требуют установку набора ПО в зависимости от отдела (бухгалтерия, юристы и тд.). Решать задачу вручную слишком долго, поэтому я выбрал Chocolatey для экономии времени, о котором уже был наслышан от коллеги.
Подводные камни:
Корпоративная сеть закрыта, поэтому нет доступа к официальному репозиторию Chocolatey.
Загрузка пакетов с мировой паутины запрещена политикой безопасности.
Исходя из этого, решение напрашивается само: развёртывание локального репозитория Chocolatey. Далее постараюсь расписать процесс максимально подробно. Приступим:
Подготовка инфраструктуры
Для реализации потребуется:
Локальный сервер или общая сетевая папка для хранения пакетов.
PowerShell 5+ с правами администратора.
Пакеты .nupkg (в моём случае - собранные вручную).
Варианты локального репозитория:
NuGet.Server - самый простой вариант для Windows.
Nexus Repository - гибкое решение для больших сетей.
Общая сетевая папка - быстрый и простой вариант, но со своими минусами.
В качестве итогового решения выбрал сетевую папку. Причины очень просты, оно не требует дополнительных серверных компонентов, которыми на данный момент я не располагаю. К минусам же могу отнести:
Низкая производительность при массовой установке (поэтому я буду устанавливать ПО, разбив установку на группы по 20-25 машин).
Отсутствие контроля версий как в полноценных репозиториях.
Начнем с установки Chocolatey в закрытой корпоративной сети. Для начала нам нужно скачать установочный файл (chocolatey.2.4.3.nupkg) с официального сайта Chocolatey. Далее выполняем перечень команд:
# Переходим в папку с .nupkg cd "C:\Users\Admin\Desktop" # Распоковываем .nupkg как архив Rename-Item -Path "chocolatey.2.4.3.nupkg" -NewName "chocolatey.2.4.3.zip" Expand-Archive -Path "chocolatey.2.4.3.zip" -DestinationPath "C:\ChocoInstall" -Force # Запускаем установку Set-ExecutionPolicy Bypass -Scope Process -Force & "C:\ChocoInstall\tools\chocolateyInstall.ps1" # Проверяем корректность установки choco --version
Создание собственного пакета для распространения
Перед созданием пакета потребуется:
Установленный Chocolatey на машине разработчика;
Доступ к установочным файлам в сетевой папке;
Права администратора на машине, где создаём пакет;
Текстовый редактор для изменения файлов пакета (VS Code, Notepad++, Блокнот).
Если все требования соблюдены - приступим к созданию:
Генерируем нашу заготовку .nuspec:
choco new buh
Команда создаст шаблон в папке buh (данный пакет мы направим на машины бухгалтеров):

Редактируем buh.nuspec в текстовом редакторе:
<?xml version="1.0" encoding="utf-8"?> <package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd"> <metadata> <id>buh-software</id> <version>1.0.0</version> <title>ПО для бухгалтерии</title> <authors>Ваша организация</authors> <description>Пакет стандартного ПО для отдела бухгалтерии</description> <tags>бухгалтерия 1с контур office</tags> </metadata> <files> <file src="tools\**" target="tools\" /> </files> </package>
Редактируем chocolateyinstall.ps1:
# Политика обработки ошибок: выполняет остановку скрипта при любой ошибке $ErrorActionPreference = 'Stop' # Параметры установки $installers = @( @{ Name = '1C'; Path = "\\IT\software\buh\1C\setup.exe"; Args = "/S"; Shortcut = "C:\Program Files\1C\1CEStart.exe" }, @{ Name = 'KonturExtern'; Path = "\\IT\software\buh\KonturExtern\install.msi"; Args = "/i `"$($_.Path)`" /qn"; Process = "msiexec.exe" }, @{ Name = 'BankClient'; Path = "\\IT\software\buh\BankClient\setup.exe"; Args = "/S" }, @{ Name = 'Office'; Path = "\\IT\software\buh\Office\setup.exe"; Args = "/configure configuration.xml" } ) # Установка всех программ foreach ($app in $installers) { try { $process = Start-Process -FilePath ($app.Process ?? $app.Path) -ArgumentList $app.Args -Wait -PassThru if ($process.ExitCode -ne 0) { throw "Exit code $($process.ExitCode)" } Write-Host "$($app.Name) установлен успешно" -ForegroundColor Green } catch { Write-Warning "Ошибка установки $($app.Name): $_" } } # Создание ярлыка (у меня только для 1С по просьбе бухгалтерии) if (Test-Path $installers[0].Shortcut) { $WshShell = New-Object -ComObject WScript.Shell $Shortcut = $WshShell.CreateShortcut("$env:Public\Desktop\1C Предприятие.lnk") $Shortcut.TargetPath = $installers[0].Shortcut $Shortcut.Save() }
Собираем готовый пакет:
choco pack
Возможно потребуется использование:
cd C:\Users\Admin\Desktop\buh # После выполнения команды повторяем 'choco pack'
Наш пакет в расширении .nupkg готов, копируем в сетевую папку и проверяем работоспособность пакета на тестовой машине:
choco install buh-software -y --source="';\\IT\Software\choco'" --force
Возможные проблемы и их решения
В процессе внедрения автоматической установки пакетов в корпоративной среде я столкнулся с рядом нюансов, которые могут помешать развёртыванию. Далее перечислю самые распространённые проблемы и способы их обхода:
Ошибки доступа к общей папке: скрипт выдаёт ошибку "Access denied" или "Network path not found".
Необходимо проверить права УЗ, с которой выполняется скрипт. У неё должны быть права на чтение/запись;
Возможно потребуется добавить исключение в брандмауэр:
New-NetFirewallRUle -DisplayName "Allow SMB for Chocolatey" -Direction Inbound -Protocol TCP -LocalPort 445 -Action Allow
Долгая установка на некоторых машинах: логи показывают таймаут или скрипт вовсе зависает на отдельных машинах.
Сократить список до 15-20 машин (пример с разбивкой указан ниже);
Добавить -ThrottleLimit 10 в Invoke-Command чтобы ограничить параллельные сессии.
Развёртывание ПО на машинах
После подготовки пакетов необходимо развернуть ПО на всех машинах. Для себя выбрал установку через PowerShell Remoting, но есть и альтернативный вариант через GPO.
Альтернативный вариант через GPO
Создание нового GPO;
Настройка задания (обязательно установить галку на "run with higest privileges");
Добавить триггер "at startup" (или по расписанию, если вам удобнее);
Действия:
Действие: start a program
Программа: powershell.exe
Аргументы:
-NoProfile -ExecutionPolicy Bypass -Command "choco install buh-software -y --source='\IT\Software\choco' --cache-location='C:\Windows\Temp\choco'"
Доп. параметры:
Включаем опцию "run task as soon as possible after a scheduled start is missed"
Устанавливаем "stop the task if it runs longer than" 2 часа
В примере установка только на 23 машины бухгалтеров. Для развёртывания на все машины разом (без разделения на отделы) можно использовать разбивку на группы (по 20 единиц):
$groups = $computers | Select-Object -First 100 | Select-Object -Skip 0 -First 20
Использовать для развёртывания будем скрипт:
# Импорт из .csv + фильтр для бухов $computers = Import-Csv -Path "C:\IT\Deployment\computers.csv" | Where-Object { $_.Department -eq "Бухгалтерия" } | Select-Object -ExpandProperty ComputerName # Проверяем компьютеры if (-not $computers) { Write-Warning "Не найдено компьютеров отдела Бухгалтерия в CSV файле" exit } # Путь к ZIP-архиву с Chocolatey на сетевой шаре $chocoZipPath = "\\IT\Software\choco\chocolatey.zip" # Временный каталог для распаковки на машинах $tempChocoPath = "C:\Temp\ChocolateyInstall" foreach ($computer in $computers) { try { # Проверяем доступность машины if (-not (Test-Connection -ComputerName $computer -Count 1 -Quiet -ErrorAction SilentlyContinue)) { Write-Warning "$computer недоступен" Add-Content -Path "C:\IT\Deployment\failed.txt" -Value "$computer - недоступен по сети" continue } # Устанавливаем Chocolatey из архива $session = $null try { # Создаем сессию $session = New-PSSession -ComputerName $computer -ErrorAction Stop Invoke-Command -Session $session -ScriptBlock { param($zipPath, $installPath) # Создаем временный каталог if (-not (Test-Path $installPath)) { New-Item -ItemType Directory -Path $installPath -Force | Out-Null } # Копируем архив на целевую машину $localZipPath = Join-Path $env:TEMP "chocolatey.zip" Copy-Item -Path $zipPath -Destination $localZipPath -Force # Распаковываем архив try { Add-Type -AssemblyName System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipPath, $installPath) } catch { Write-Warning "Ошибка распаковки Chocolatey: $_" throw } # Добавляем путь к Chocolatey в переменную PATH $chocoBinPath = Join-Path $installPath "tools" $envPath = [Environment]::GetEnvironmentVariable("PATH", "Machine") if (-not $envPath.Contains($chocoBinPath)) { [Environment]::SetEnvironmentVariable( "PATH", "$envPath;$chocoBinPath", "Machine" ) $env:PATH += ";$chocoBinPath" } # Устанавливаем переменную окружения ChocolateyInstall [Environment]::SetEnvironmentVariable( "ChocolateyInstall", $installPath, "Machine" ) # Добавляем локальный репозиторий Start-Sleep -Seconds 5 # Даем время для инициализации & choco source add -n="LocalRepo" -s="\\IT\Software\choco" --priority=1 -ErrorAction Stop # Устанавливаем пакет & choco install buh-software -y --source=LocalRepo --force -ErrorAction Stop # Очищаем временные файлы Remove-Item $localZipPath -Force -ErrorAction SilentlyContinue } -ArgumentList $chocoZipPath, $tempChocoPath -ErrorAction Stop Write-Host "$computer : установка завершена успешно" -ForegroundColor Green } catch { Write-Warning "Ошибка на $computer : $_" Add-Content -Path "C:\IT\Deployment\failed.txt" -Value "$computer - ошибка установки: $_" } finally { if ($session) { Remove-PSSession -Session $session } } } catch { Write-Warning "Ошибка при обработке $computer : $_" Add-Content -Path "C:\IT\Deployment\failed.txt" -Value "$computer - ошибка обработки: $_" } }
После успешного развёртывания ПО на всех машинах удалось достичь следующего:
Временные показатели:
Ручная установка занимает ~40 минут на машину × 100 = ~66 часов;
Установка с помощью Chocolatey: ~10 часов (с подготовкой и созданием 5 пакетов для разных отделов);
Экономия: 56 часов рабочего времени.
Масштабируемость:
Данное решение готово к развёртыванию на новых машинах/обновлению ПО на старых;
Процесс установки новых версий ПО упрощён в разы.
Итог
Решение, описанное в статье, позволяет развёртывать и создавать собственные пакеты ПО для разных нужд и отделов на множестве корпоративных компьютеров с минимальными затратами труда.
Данный подход не является совершенным, что было описано в начале статьи. Опыт показал, что решение хоть и легко масштабируется, но является не самым быстрым. Для себя решил, что обязательно буду рассматривать внедрение Nexus Repository или его аналогов.
В заключение, если у вас остались какие-то вопросы - буду рад помочь, обсудить. Если метод несовершенен - обязательно пишите комментарии, всё прочитаю, изучу, исправлю. Надеюсь, что моё решение натолкнёт вас на интересные мысли или поможет по аналогии автоматизировать работу в своей организации! Внедряйте, автоматизируйте, пусть рутина останется позади!
P.S. В моей группе в Телеграмм разбираем практические кейсы: скрипты (Python/Bash/PowerShell), тонкости ОС и инструменты для эффективной работы.
