
Представьте: ваша организация закупила 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. Я запустил свою группу в Телеграмм, буду рад видеть всех, кому интересен процесс написания скриптов и автоматизация в мире IT.
NekoYos
Прочитав статью сразу вопрос - актив директори+груповые политики для автоматической установки нужного ПО штатными средствами винды в корпоративной среде не рассматривали? Зачем городить скрипты и сторонние инструменты если майкрософт очень как давно все для этого сделала?
eternaladm Автор
Отличный вопрос! Вы абсолютно правы — GPO + AD действительно базовое решение, и мы начали именно с него. Но в реальных условиях столкнулись с ограничениями: когда нужно не просто установить ПО, а поддерживать актуальные версии, оперативно откатывать обновления при конфликтах или гибко настраивать параметры установки для разных отделов, Chocolatey оказался незаменим.
Мы не отказывались от GPO полностью, он все еще используется для задач вроде установки браузеров/ридеров и прочего ПО, где не требуется строгий контроль версий и тягомотная установка (как в той же 1С).
Для нас, для меня лично, Chocolatey закрыл те сценарии, где штатных средств недостаточно или они требуют слишком много ручной работы. Как и было сказано в конце статьи, я обязательно рассмотрю Nexus для контроля версий, для доработки нынешней системы, так как на практике это оказалось в разы удобнее для большого количества машин.
Если у Вас есть подобный опыт, но он был реализован через GPO - буду рад, если Вы поделитесь!
Busla
Я, конечно, не знаю: как у вас в организации оно реально устроено; но в примере из статьи фичи Chocolatey не то что не используются, а скорее даже сломаны.
Каждое приложение стоило бы собрать в отдельный пакет с реальной версией этого ПО. А buh-software сделать метапакетом - который сам по себе ничего не содержит, кроме списка зависимостей от других пакетов.
Вместе с choco ставятся модули powershell где реализована и установка из msi, и создание ярлыков с дополнительной "магией" для, например, автоматического удаления этих ярлыков при удалении пакета. Вы же и штатную автоматизацию не использовали, и явно обновление и удаление не заскриптовали.
Не очень понятно: что вы хотите получить от Nexus? - в файловом nuget-репозитории точно так же рядом прекрасно сосуществуют разные версии одного пакета.
eternaladm Автор
Спасибо за комментарий! Вы абсолютно правы в своей критике. Полностью признаю, мой подход в статье далёк от идеала и не использует все возможности Chocolatey.
Действительно, каждое приложение должно быть отдельным пакетом с версионированием, в статье данный момент действительно упущен.
Полностью согласен, в статье подобное не реализовано. Постараюсь углубиться в тему и внести правки.
Это один из вариантов реализации моего решения не с сетевой папки. Как и было сказано в начале, мой способ не подходит для массовой работы с пакетами из-за низкой скорости.
Моё решение помогло справиться с задачей, но в силу первого опыта работы с Chocolatey и сжатых сроков - действительно вышло не самым "правильным".
Большое спасибо Вам за подробный разбор и правильную критику! Если вы можете подсказать какие-то аналоги Nexus (мне нужен именно отдельный сервер) - буду крайне признателен за помощь!