Надёжная установка программ средствами групповых политик без SCCM
Воскресенье, 26 - Апрель - 2015 9 комментариев
Централизованно устанавливать программы в домене Active Directory можно либо средствами групповых политик (Group Policy), либо инструментарием наподобие System Center Configuration Manager. Но SCCM — мероприятие недешёвое, поэтому весомая часть системных администраторов распространяет MSI-пакеты политиками. Однако, установка политиками обладает рядом существенных недостатков:
- Если инсталляция не удалась с первого раза, она никогда не будет исполнена до конца. Причины сбоя установки могут быть разными, но политика так или иначе создаст в реестре клиентской машины запись «Объект политики с таким-то номером отработал, дело можно закрыть». Идентификатор объекта вы можете найти в ключе HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\AppMgmt. Получается, системе безразлично, нормально ли установилась программа — она регистрирует лишь факт исполнения политики, чтобы потом к этому вопросу больше уже не возвращаться.
- Если так случилось, что установленную политикой программу кто-то убрал вручную, она не будет возвращена на место автоматически. Проблема известная, вот где я нашёл объяснение, когда столкнулся с ней впервые: https://social.technet.microsoft.com/Forums/windowsserver/en-US/82f1e144-78a3-4446-8aaf-18843c890cdc/force-reinstall-of-applications-deployed-by-software-gpo-after-uninstall. Причина всё та же, что в пункте номер раз.
- Иногда требуется задавать особые условия установки или проверки предварительных условий, которые стандартные политики не поддерживают. Например, при инсталляции Oracle VirtualBox добавить сертификат доверенного издателя:
"%~dp0\cert\VBoxCertUtil.exe" add-trusted-publisher "%~dp0\cert\oracle-vbox.cer"
Для решения этих проблем я написал скрипты распространения и убирания программ. Стандартная схема централизованного распространения может выглядеть так:
- На одном из контроллеров в шаринге NetLogon создаём папку Deployment, внутри которой размещаем папки всех нужных приложений, например:
\\DC-Riga.WindowsNT.LV\NetLogon\Deployment\7-Zip
\\DC-Riga.WindowsNT.LV\NetLogon\Deployment\Skype
\\DC-Riga.WindowsNT.LV\NetLogon\Deployment\FrontMotion_Firefox
Такое местоположение удобно тем, что контроллеры реплицируют содержимое папки NetLogon между собой, а путь инсталляции можно назначить в виде доменного имени \\WindowsNT.LV\NetLogon\Deployment; в результате, клиенты выполнят установку с ближайшего контроллера. - Внутри папки конкретного приложения сохраняем скрипты установки и убирания приложения:
\…\7-ZIP
\…\7-ZIP\x64\7z920-x64.msi
\…\7-ZIP\x86\7z920-x86.msi
\…\7-ZIP\Install_7Zip.bat
\…\7-ZIP\Uninstall_7Zip.bat - Создаём отдельные объекты групповых политик Applications 7-Zip Install и Applications 7-Zip Uninstall, в которых указываем скрипты в секции Startup Scripts. Политики пристёгиваем к нужному контейнеру в Active Directory (например, к корню домена или только к требуемым департаментам). Можно создать группы безопасности, куда внести учётные записи нужных машин, затем разрешить применять политики только этим группам.
Теперь собственно скрипт установки на простом примере 7-Zip:
rem Application Install - 7-Zip set Package_Name_x86=x86\7z920.msi set Package_Name_x64=x64\7z920-x64.msi set MSI_Product_Code_x86={23170F69-40C1-2701-0920-000001000000} set MSI_Product_Code_x64={23170F69-40C1-2702-0920-000001000000} set Installation_Parameters= set Desired_Version=0x9140000 set Detected_Version=None:Check_if_already_installed_x64_on_x64 REG QUERY HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\%MSI_Product_Code_x64% if not %ErrorLevel%==0 goto Check_x86_on_x86 for /f "tokens=2,*" %%a in ('REG QUERY HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\%MSI_Product_Code_x64% /v Version ^| findstr Version') do set Detected_Version=%%b if /i (%Detected_Version%)==(%Desired_Version%) goto End goto Install:Check_if_already_installed_x86_on_x86 REG QUERY HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\%MSI_Product_Code_x86% if not %ErrorLevel%==0 goto Check_x86_on_x64 for /f "tokens=2,*" %%a in ('REG QUERY HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\%MSI_Product_Code_x86% /v Version ^| findstr Version') do set Detected_Version=%%b if /i (%Detected_Version%)==(%Desired_Version%) goto End goto Install:Check_if_already_installed_x86_on_x64 REG QUERY HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\%MSI_Product_Code_x86% if not %ErrorLevel%==0 goto Install for /f "tokens=2,*" %%a in ('REG QUERY HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\%MSI_Product_Code_x86% /v Version ^| findstr Version') do set Detected_Version=%%b if /i (%Detected_Version%)==(%Desired_Version%) goto End:Install if /i exist "C:\Program Files (x86)" goto Install_x64 :Install_x86 xcopy /r /y "%~dp0%Package_Name_x86%" "%Temp%\%Package_Name_x86%*" msiexec /i "%Temp%\%Package_Name_x86%" %Installation_Parameters% /qn del /f /q "%Temp%\%Package_Name_x86%" goto End :Install_x64 msiexec /i "%~dp0%Package_Name_x64%" %Installation_Parameters% /qn :End
Cкрипт убирания программы:
rem Application Uninstall - 7-Zip set MSI_Product_Code_x86={23170F69-40C1-2701-0920-000001000000} set MSI_Product_Code_x64={23170F69-40C1-2702-0920-000001000000} set Installation_Parameters=/norestart:Check_x64_on_x64 REG QUERY HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\%MSI_Product_Code_x64% if %ErrorLevel%==0 msiexec /x %MSI_Product_Code_x64% %Installation_Parameters% /qn:Check_x86_on_x86 REG QUERY HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\%MSI_Product_Code_x86% if %ErrorLevel%==0 msiexec /x %MSI_Product_Code_x86% %Installation_Parameters% /qn:Check_x86_on_x64 REG QUERY HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\%MSI_Product_Code_x86% if %ErrorLevel%==0 msiexec /x %MSI_Product_Code_x86% %Installation_Parameters% /qn:End
Дополнительные замечания:
- Скрипт установки требует настройки шести переменных: Package_Name_x86, Package_Name_x64, MSI_Product_Code_x86, MSI_Product_Code_x64, Installation_Parameters, Desired_Version, для каждой программы они уникальны. Коды MSI и версию программы я выясняю отдельно, устанавливая программу вручную на тестовых системах.
- Разумеется, инсталляции можно запускать не с контроллеров, а из выделенной точки распространения вида \\DeploymentServer.WindowsNT.LV. Учтите, что компьютеры считывают инсталляционные файлы от лица ComputerName$/SYSTEM — убедитесь, что группы Domain Computers и Domain Controllers имеют разрешения чтения как на Share, так и на NTFS.
- В любом случае, убедитесь, что путь к выбранному репозиторию добавлен в «белые списки» программ (Application Whitelisting), иначе установка может отказать и по этой причине.
- Команда XCopy в %Temp% нужна только для Windows XP/2003, так как на этих системах MSIExec не умеет инсталлировать с сетевых ресурсов. На более новых системах копировать исходник на локальную машину не нужно, можно выполнять команду msiexec напрямую из %~dp0, как это сделано в 64-разрядном блоке.
- Загрузочные скрипты на Windows 8 по умолчанию не работают. Причина: Windows 8 на самом деле не выключается (не выполняет Shutdown) — вместо этого, система всегда пытается выполнить Hybrid Sleep. Как окончательное решение, пришлось просто запретить Hybrid Sleep политиками для всех Windows 8.
- Для подсчёта процента компьютеров с успешно установленной программой (Compliance) используйте Group Policy Preferences: https://blog.windowsnt.lv/2014/09/22/srp-compliance-report-russian/
задумка хорошая, но со своими нюансами. не всегда проверка на наличие установленной утвержденной в производство версии достаточно, ибо не все программы поддерживают update/downgrade (например java). Google Chrome, так тот вообще использует ветку регистра wow6432 как для 64 так и 32-бит версии. но вопрос в другом: как заставить все скрипты за раз, а не по-одному за перезагрузку?
Качеством проверок озаботьтесь самостоятельно. А вот со всеми скриптами — вопрос интересный.
Я сейчас пытаюсь делать инсталляции с помощью WSUS Package Publisher. Не готов ответить на все вопросы, но уже более-менее получается. Рекомендую.
Явный плюс — установки обновлений производятся во время работы системы, а не при перезагрузках.
Спасибо за рекомендацию WSUS Package Publisher. С нового года начал развертывать софт при помощи WPP (до этого пытался начинать с LUP, но не пошло). Действительно, удобно тем, что программы ставятся в фоне в заданное время. И не нужно ждать перезагрузку (а пользователи у нас работают посменно, компьютеры перегружаются редко).
Ещё через WPP я начал собирать Compliance Reports.
Добрый день. Подскажите, пожалуйста, в домене (2012R2) есть машины с Win7 pro и Win 8.1 pro. В групповых политиках добавил автозапуск скрипта для установки Chrome. На Win7 скрипт отрабатывает нормально, на этих машинах программа установилась. На Win 8.1 скрипт не срабатывает. В чем может быть проблема? По железу основное отличие, все Win 8.1 установлены на SSD, Win 7 на HDD.
Скрипт должен отрабатывать при старте, а W8 не перезагружается по умолчанию. Вместо выключения она уходит в Hybrid Sleep, что отключается отдельной политикой. Таки рекомендую устанавливать программы через WSUS Package Publisher, получите множество дополнительных преимуществ.
Добрый день. Есть пара ошибок в скриптах:
В обоих скриптах в первой строчке назначение переменной ушло в строчку с комментарием:
rem Application Install — 7-Zipset Package_Name_x86=x86\7z920.msi
В скрипте установки используется передача выполнения кода по ссылке вида Check_x86_on_x86, при этом в самом скрипте ссылки выглядят по-другому, например :Check_if_already_installed_x86_on_x86
Благодарю за комментарий!
Для меня актуальность вопроса снизилась после применения WSUS Package Publisher .) но обновлю всё равно.
Проверил:
1. видимо, set так передаётся в каком-то браузере, у меня всё отображается корректно: set находится на следующей строчке после rem.
2. метки Check_if_already_installed для переходов не используются, я их использовал для комментирования