
Представьте: ваша организация закупила 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.