• SCCM 2007 R2 – развёртывание Java Runtime Environment (JRE)

    Просматривая отчет SCCM ‘Count of all instances of software registered with Add or Remove Programs’ обратил внимание на огромный букет разных версий Java Runtime Environment (JRE), установленных на разных клиентских системах. Выяснилось, что на некоторых клиентах установлено по несколько экземпляров JRE, как разных веток, так и их подверсий. Погуглив, почитав гневные выплески в адрес разработчиков и поигравшись с дистрибутивами JRE, стало понятно, что развернуть актуальную версию JRE параллельно удалив при этом все старые версии – задача не совсем тривиальная. Дополнительно нужно решить проблему отключения механизма обновления, который приводит в замешательство пользователей, периодически выбрасывая окно UAC при попытке произвести авто-обновление JRE.

    Для начала нам необходимо скачать последнюю версию (на момент написания заметки это версия 6 Update 23) offline-инсталлятора с адреса Java Runtime Environment Download

    Итак, у нас имеются два файла:
    jre-6u23-windows-i586.exe – для 32-битных версий Windows
    jre-6u23-windows-x64.exe – для 64-битных версий Windows

    Для развёртывания через SCCM, так же как и через другие механизмы типа GPO, нам понадобиться файлы MSI инсталлятора. О том, как их извлечь описано в статье How do I deploy Java using Active Directory across a network?
    Запускаем полученный *.exe дистрибутив (сам процесс установки при этом выполнять не нужно)…

    image

    …переходим в служебный каталог, куда после запуска дистрибутив JRE распаковывает свои файлы (в зависимости от используемой ОС каталог может различаться):

    для Windows Vista/7 - C:Users<user>AppDataLocalLowSunJavajre1.6.0_23
    для Windows XP - C:Documents and Settings<user>Local SettingsApplication DataSunJava jre1.6.0_23

    Копируем из этого каталога файлы jre1.6.0_23.msi и Data1.cab и после этого запущенное приложение программы установки JRE можно закрывать (оно нам больше не понадобиться).

    Так как *.cab файл в составе дистрибутива имеет цифровую подпись, перед началом развёртывания необходимо удостовериться в том, что на целевых клиентских системах обновлено хранилище корневых сертификатов. В противном случае, мы можем столкнуться с проблемой, описанной в заметке SCCM – Обновление корневых сертификатов.

    Файлы необходимые для установки новой версии мы получили, но как быть с множеством уже установленных экземпляров старых версий? Для того чтобы произвести их удаление перед установкой новой версии создадим отдельный пакетный файл jre1.6.0_23_UninstallAll.bat следующего содержания:

    rem Java(TM) 6 Update 23
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216023FF} /qn
    rem Java(TM) 6 Update 23 (64-bit)
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F86416023FF} /qn
    rem Java(TM) 6 Update 22
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216022FF} /qn
    rem Java(TM) 6 Update 21
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216021FF} /qn
    rem Java(TM) 6 Update 20
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216020FF} /qn
    rem Java(TM) 6 Update 19
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216019FF} /qn
    rem Java(TM) 6 Update 18
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216018F0} /qn
    rem Java(TM) 6 Update 17
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216017FF} /qn
    rem Java(TM) 6 Update 17 (64-bit)
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F86416017FF} /qn
    rem Java(TM) 6 Update 16
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216016FF} /qn
    rem Java(TM) 6 Update 15
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216015FF} /qn
    rem Java(TM) 6 Update 14
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216014FF} /qn
    rem Java(TM) 6 Update 13
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216013FF} /qn
    rem Java(TM) 6 Update 12
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216012FF} /qn
    rem Java(TM) 6 Update 11
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216011FF} /qn
    rem Java(TM) 6 Update 10
    msiexec.exe /x {26A24AE4-039D-4CA4-87B4-2F83216010FF} /qn

    rem =====================================
    rem Java(TM) 6 Update 7
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0160070} /qn
    rem Java(TM) 6 Update 6
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0160060} /qn
    rem Java(TM) 6 Update 5
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0160050} /qn
    rem Java(TM) 6 Update 4
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0160040} /qn
    rem Java(TM) 6 Update 3
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0160030} /qn
    rem Java(TM) 6 Update 2
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0160020} /qn
    rem Java(TM) SE Runtime Environment 6 Update 1
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0160010} /qn
    rem Java(TM) SE Runtime Environment 6
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0160000} /qn

    rem =====================================
    rem JRE Runtime Environment 5.0 Update 21
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150210} /qn
    rem JRE Runtime Environment 5.0 Update 20
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150200} /qn
    rem JRE Runtime Environment 5.0 Update 19
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150190} /qn
    rem JRE Runtime Environment 5.0 Update 18
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150180} /qn
    rem JRE Runtime Environment 5.0 Update 17
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150170} /qn
    rem JRE Runtime Environment 5.0 Update 16
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150160} /qn
    rem J2SE Runtime Environment 5.0 Update 15
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150150} /qn
    rem JRE Runtime Environment 5.0 Update 14
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150140} /qn
    rem JRE Runtime Environment 5.0 Update 13
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150130} /qn
    rem J2SE Runtime Environment 5.0 Update 12
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150120} /qn
    rem JRE Runtime Environment 5.0 Update 11
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150110} /qn
    rem JRE Runtime Environment 5.0 Update 10
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150100} /qn
    rem JRE Runtime Environment 5.0 Update 9
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150090} /qn
    rem JRE Runtime Environment 5.0 Update 8
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150080} /qn
    rem JRE Runtime Environment 5.0 Update 7
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150070} /qn
    rem J2SE Runtime Environment 5.0 Update 6
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150060} /qn
    rem JRE Runtime Environment 5.0 Update 5
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150050} /qn
    rem JRE Runtime Environment 5.0 Update 4
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150040} /qn
    rem J2SE Runtime Environment 5.0 Update 3
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150030} /qn
    rem J2SE Runtime Environment 5.0 Update 2
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150020} /qn
    rem JRE Runtime Environment 5.0 Update 1
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150010} /qn
    rem JRE Runtime Environment 5.0
    msiexec.exe /x {3248F0A8-6813-11D6-A77B-00B0D0150000} /qn

    rem =====================================
    rem Java 2 Runtime Environment, SE v1.4.2_19
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142190} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_18
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142180} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_17
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142170} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_16
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142160} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_15
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142150} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_14
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142140} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_13
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142130} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_12
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142120} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_11
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142110} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_10
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142100} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_09
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142090} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_08
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142080} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_07
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142070} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_06
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142060} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_05
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142050} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_04
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142040} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_03
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142030} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_02
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142020} /qn
    rem Java 2 Runtime Environment, SE v1.4.2_01
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142010} /qn
    rem Java 2 Runtime Environment, SE v1.4.2
    msiexec.exe /x {7148F0A8-6813-11D6-A77B-00B0D0142000} /qn

    rem =====================================
    rem Java 2 Runtime Environment Standard Edition v1.3.1_25
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_25Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_24
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_24Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_23
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_23Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_22
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_22Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_21
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_21Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_20
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_20Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_19
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_19Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_18
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_18Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_17
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_17Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_16
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_16Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_15
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_15Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_14
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_14Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_13
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_13Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_12
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_12Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_11
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_11Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_10
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_10Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_09
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_09Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_08
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_08Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_07
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_07Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_06
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_06Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_05
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_05Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_04
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_04Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_03
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_03Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_02
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_02Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3.1_01
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3.1_01Uninst.isu" –a
    rem Java 2 Runtime Environment Standard Edition v1.3
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.3Uninst.isu" -a

    rem =====================================
    rem Java 2 Runtime Environment Standard Edition v1.2
    %systemroot%IsUninst.exe -f"%SystemDrive%Program FilesJavaSoftJRE1.2Uninst.isu" -a

    rem =====================================
    rem Java Auto Updater 2.0.2.1 / 2.0.2.4
    MsiExec.exe /x {4A03706F-666A-4037-7777-5F2748764D10} /qn

    В начале файла удаление уже установленного экземпляра текущей версии фигурирует не случайно. Эксперименты показали что если текущая версия была ранее установлена в ручную то выкорчевать из неё логику механизма авто-обновления сложней чем просто удалить и установить заново с нужными параметрами. В конце файла строка удаления Java Auto Updater добавлена больше для перестраховки, так как, при удалении JRE в штатном режиме, этот модуль удаляется тоже.

    Для информации: если нет желания удалять текущую версию JRE с установленным модулем авто-обновления, механизм авто-обновления можно попытаться отключить в реестре:

    [HKEY_LOCAL_MACHINESoftwareJavaSoftJava UpdatePolicy]
    "EnableJavaUpdate"=dword:00000000
    "EnableAutoUpdateCheck"=dword:00000000

    Разместив полученные из дистрибутива файлы jre1.6.0_23.msi , Data1.cab и пакетный файл удаления старых версий jre1.6.0_23_UninstallAll.bat в одном сетевом каталоге, в SCCM создаем пакет распространения JRE.

    image

    Пакет будет иметь две основные программы, которые мы будем использовать. Первая программа «Uninstall all old versions» будет запускать созданный нами пакетный файл для удаления старых версий

    image

    Вторая программа «Per-system unattended» будет запускать процедуру установки новой версии с необходимыми нам ключами, отвечающими за отключение механизма авто-обновления JRE

    image

    Команда установки может быть следующей:

    msiexec /i jre1.6.0_23.msi /qn REBOOT=Suppress JAVAUPDATE=0 AUTOUPDATECHECK=0

    ключи ADDLOCAL=ALL IEXPLORER=1 MOZILLA=1 можно не использовать, так как, начиная с версии JRE 6 update 10, они считаются устаревшими.

    Обратите внимание на то, что текущая версия JRE имеет два разных дистрибутива для платформ 32 и 64 бита, поэтому на закладке предварительных требований для запуска программы установки необходимо ограничить список соответствующих платформ, на которые может быть установлен данный пакет.

    image

    После того, как на SCCM пакет распространения готов, создадим коллекцию компьютеров на которую в последствие будет назначено объявление развёртывания этого пакета, с членством основанном на SQL запросе

    image

    Запрос должен выбирать из БД SCCM все компьютеры, у которых в составе установленных приложений присутствуют старые версии JRE разных веток, например, так:

    select

    SMS_R_SYSTEM.ResourceID,

    SMS_R_SYSTEM.ResourceType,

    SMS_R_SYSTEM.Name,

    SMS_R_SYSTEM.SMSUniqueIdentifier,

    SMS_R_SYSTEM.ResourceDomainORWorkgroup,

    SMS_R_SYSTEM.Client

    from SMS_R_System

    inner join SMS_G_System_ADD_REMOVE_PROGRAMS

    on SMS_G_System_ADD_REMOVE_PROGRAMS.ResourceID = SMS_R_System.ResourceId

    where  

    SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName

    like 'Java(TM) 6%' OR

    SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName

    like 'Java(TM) SE Runtime Environment 6%' OR

    SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName

    like 'J2SE Runtime Environment 5%' OR

    SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName

    like 'Java 2 Runtime Environment, SE v1.4%' OR

    SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName

    like 'Java 2 Runtime Environment Standard Edition v1.3%' OR

    SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName

    like 'Java 2 Runtime Environment Standard Edition v1.2%'

    После того как коллекция будет обновлена и заполнена компьютерами, создаем последовательность задач (Task Sequences) состоящую из двух действий. Первым действием будет запуск программы выполняющей пакетный файл удаления всех старых версий:

    image

    При этом в опциях данного шага необходимо обозначить то, что в случае возврата ошибок, последовательность будет продолжать выполняться. В ходе выполнения пакетного файла для тех продуктов, которые не установлены, будет возвращаться код ошибки инсталлятора MSI 1605, что может приводить к прерыванию последовательности. По этой же причине процедуру установки пакета предлагается выполнять не в виде обычного объявления на коллекцию, а через выполнение последовательности задач.

    image

    Вторым действием последовательности будет уже сама установка новой версии с необходимыми нам параметрами

    image

    После этого нам остаётся только объявить последовательность задач на созданную ранее коллекцию компьютеров и следить за ходом развёртывания на консоли SCCM

    image

    Дополнительные источники информации:

    Java SE Online Documentation - Java Runtime Environment Configuration
    Java SE Online Documentation - JRE Installer Options
    AppDeploy Package Knowledgebase - Java Runtime Environment
    camie.dyndns.org - J2SE & JRE Mass Uninstallation Script (Bat)
    Brad's JumpBag Blog - Java 6 Update 22 partial installs

  • SCCM - Обновление корневых сертификатов

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

    Имя журнала: Application
    Источник: MsiInstaller
    Дата: 26.01.2011 8:37:12
    Код события: 11330
    Категория задачи: Отсутствует
    Уровень: Ошибка
    Ключевые слова: Классический
    Пользователь: mydomuser
    Компьютер: WS001.mydom.com
    Описание:
    Product: Java(TM) 6 Update 23 -- Error 1330.A file that is required cannot be installed because the cabinet file \sccm-serverSourcesJRE_1.6.0_23x86Data1.cab has an invalid digital signature. This may indicate that the cabinet file is corrupt. Error 266 was returned by WinVerifyTrust.

    Проблема в данном случае заключается в отсутствии доверия к корневому сертификату в цепочке корневых сертификатов того сертификата, с помощью которого подписан *.cab файл в составе дистрибутива.

    При этом на компьютерах с Windows XP данной проблемы нет, так как эти ОС получают с WSUS соответствующее обновление - Update for Root Certificates [October 2010] (KB931125)

    clip_image001

    Для того чтобы обеспечить обновление корневых сертификатов на всех клиентских системах Windows можно скачать файл rootsupd.exe и форсированного распространить его. В моём случае, для этой цели я воспользовался SCCM, создав новый пакет распространения:

    clip_image002

    Для пакета сделана соответствующая программа, которая в скрытом режиме будет запускать исполняемый файл rootsupd.exe.

    clip_image001[4]

    После распространения созданного пакета на все точки распространения SCCM и объявления на коллекцию клиентских ПК, проблема с развёртыванием JRE будет исчерпана.

    Для тех, у кого нет возможности использовать SCCM, распространить это обновление можно и другими доступными способами, например через GPO.

  • PowerShell - Поиск неиспользуемых учетных записей пользователей и компьютеров в домене

    Для быстрого поиска в домене давно не используемых учетных записей пользователей можно использовать оснастку ‘Active Directory Users and Computers’ (dsa.msc), создав в ней запрос.

    image

    Читать далее...

  • PowerShell – Поддержание групп безопасности политики репликации паролей RODC в актуальном состоянии

    imageПри использовании контроллеров домена «только на чтение» (RODC) для каждого RODC должна быть определена доменная группа безопасности, в которую входят учетные записи пользователей, чьи учетные данные могут реплицироваться на этот RODC. В крупной географически распределённой инфраструктуре с большим количеством контроллеров домена задача поддержания состава этих групп безопасности «в рукопашную» может стать проблемой, особенно если учесть «человеческий фактор», когда например, в каком-то из удалённых подразделений местный администратор создаёт новую учетную запись доменного пользователя, а включить в группу репликации паролей эту запись забывает. Для того чтобы исключить в данном случае «человеческий фактор», можно автоматизировать данный процесс с помощью PowerShell. Рассмотрим пример скрипта, который можно включить в планировщик задач на контроллере домена на периодическое выполнение.

    Читать далее...

  • PowerShell – Поддержание группы безопасности для Password Settings objects (PSOs) в актуальном состоянии

    imageПо мотивам применения Password Settings objects (PSOs) с нацеливанием объектов PSO на доменные группы безопасности встаёт вопрос о поддержании состава этих групп в актуальном состоянии. В моём окружении все учетные записи, находящиеся в определённом OU, должны быть включены в доменную группу безопасности, к которой применяется PSO, что само по себе уже есть критерий, по которому можно автоматизировать задачу поддержания группы в актуальном состоянии с помощью PowerShell. Представляю соответствующий скрипт.

    Читать далее...

  • AD DS - Создание нескольких политик паролей Password Settings objects (PSOs) в домене Windows Server 2008/2008 R2

    imageВ службах AD DS Windows Server 2008 появился новый механизм AD DS Fine-Grained Password and Account Lockout Policy, позволяющий в рамках домена создавать несколько разных политик паролей, применяемых к конкретным доменным пользователям или доменным глобальным группам безопасности. Такой механизм может быть полезен в случае, если, например, необходимо для определенной группы пользователей иметь ослабленные/усиленные политики безопасности, отличающиеся от тех, что заданы на уровне всего домена в Default Domain Policy.

    Рассмотрим сценарий создания объекта PSO в домене соответствующего следующим критериям:

    clip_image001

    clip_image002

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

    clip_image003

     

    Создание объекта PSO с помощью MMC-оснастки Active Directory Services Interface editor (ADSI Edit)

    Откроем оснастку ADSIEDIT.MSC и подключимся к контексту именования по умолчанию нашего домена указав в поле Name FQDN имя нашего домена

    clip_image004

    Перейдём в контейнер DC=holding, DC=com -> CN=System -> CN=Password Settings Container

    clip_image005

    И в контекстном меню на контейнере Password Settings Container выберем создание нового объекта PSO (msDC-PasswordSettings)

    clip_image006

    Укажем имя нашего нового объекта PSO

    clip_image007

    Укажем значение атрибута msDS-PasswordSettingsPrecedence. Значение этого атрибута определяет приоритет в случае конфликта нескольких PSO, применяемых к одной и той же группе безопасности или пользователю.

    clip_image008

    Значение атрибута msDS-PasswordReversibleEncryptionEnabled определяет возможность обратимого шифрования пароля для учетных записей пользователей. Устанавливаем его в false как рекомендуемое.

    clip_image009

    Зададим значение атрибута msDS-PasswordHistoryLength определяющего количество неповторяемых паролей для учетных записей пользователей.

    clip_image010

    Значение атрибута msDS-PasswordComplexityEnabled, установленное нами в true, определяет включение требования соблюдения сложности паролей и является рекомендуемым.

    clip_image011

    Значение атрибута msDS-MinimumPasswordLength, установленное нами в 8, определяет минимальную длину паролей учетных записей пользователей.

    clip_image012

    Значение атрибута msDS-MinimumPasswordAge, установленное нами в 1:00:00:00 (1 день), определяет минимальный срок действия паролей учетных записей пользователей.

    clip_image013

    Значение атрибута msDS-MaximumPasswordAge, установленное нами в 90:00:00:00 (90 дней), определяет максимальный срок действия паролей учетных записей пользователей.

    clip_image014

    Значение атрибута msDS-LockoutThreshold, установленное нами в 5, определяет порог блокировки учетных записей пользователей (после 5 неудачных попыток авторизации срабатывает механизм блокировки учетной записи).

    clip_image015

    Значение атрибута msDS-LockoutObservationWindow, установленное нами в 0:00:30:00 (30 минут), определяет период сброса счетчика блокировок учетных записей пользователей.

    clip_image016

    Значение атрибута msDS-LockoutDuration, установленное нами в 0:00:30:00 (30 минут), определяет продолжительность блокировки заблокированных учетных записей пользователей.

    clip_image017

    На этом работа мастера создания PSO завершается.

    clip_image018

    После того как только что созданный объект PSO появляется в консоли, открываем его свойства.

    clip_image019

    Среди списка атрибутов находим атрибут msDS-PSOAppliesTo и убедившись в том что его значение не определено, открываем его редактирование.

    clip_image020

    В окне редактирования Multi-valued Distinguished Name With Security Principal Editor нажимаем Add Windows Account и выбираем соответствующую доменную глобальную группу безопасности, которую мы создали ранее.

    clip_image021

    clip_image022

    Сохраняем свойства объекта PSO и убеждаемся в том, что привязка к соответствующей группе безопасности произведена (для этого можно проверить значение атрибута msDS-PSOApplied в свойствах самой группы безопасности).

    clip_image023

    Теперь на всех пользователей, включенных в эту группу безопасности, будут действовать параметры, заданные в нашем объекте PSO независимо от текущих настроек в Default Domain Policy.

    Создание объекта PSO с посмощью CLI-утилиты LDIF Directory Exchange (LDIFDE)

    Помимо создания объекта PSO через оснастку ADSIEDIT.MSC, мы можем создать его с помощью утилиты командной строки LDIFDE. В некоторых сценариях это может быть более быстро и удобно. Для этого нам предварительно нужно подготовить файл в формате *.LDF (LDAP Data Interchange Format) следующего содержания:

    dn: CN=KOM-SRV-PSO-Users,CN=Password Settings Container,CN=System,DC=holding,DC=com
    changetype: add
    objectClass: msDS-PasswordSettings
    msDS-MaximumPasswordAge: -77760000000000
    msDS-MinimumPasswordAge:-864000000000
    msDS-MinimumPasswordLength:8
    msDS-PasswordHistoryLength:5
    msDS-PasswordComplexityEnabled:TRUE
    msDS-PasswordReversibleEncryptionEnabled:FALSE
    msDS-LockoutObservationWindow:-18000000000
    msDS-LockoutDuration:-18000000000
    msDS-LockoutThreshold:5
    msDS-PasswordSettingsPrecedence:1
    msDS-PSOAppliesTo:CN=KOM-SRV-PSO-Users,CN=Users,DC=holding,DC=com

    Обратите внимание на то, что значения атрибутов связанных со временем указываются в формате I8 (интервалы по -100 наносекунд). Преобразование в данный формат производится по следующей схеме

    Единица времени

    Множитель

    1 минута

    -60*(10^7) = - 600000000

    1 час

    -60*60* (10^7) = -36000000000

    1 день

    -24*60*60*(10^7) = -864000000000

    То есть, например, чтобы установить значение атрибута msDS-LockoutDuration равным 30 минутам, для получения значения в формате I8 нужно умножить 30 на -600000000 (в этом примере значение равно -18000000000). Более подробную информацию по этому поводу можно получить в приложении Appendix B: PSO Attribute Constraints

    После того как мы подготовили LDF файл, произведём импорт указанной в нём информации командой:

    LDIFDE -i -f NewPSO.ldf

    clip_image024

    Более подробную информацию об использовании утилиты LDIFDE можно найти в статье KB237677 - Использование средства LDIFDE для импорта и экспорта объектов каталогов в Active Directory

    Дополнительные источники информации:

    Windows Server TechCenter - AD DS Fine-Grained Password and Account Lockout Policy Step-by-Step Guide

    TechDays.ru - Active Directory: политика паролей

  • Powershell - Сброс SusClientId на проблемных клиентах Windows Update в домене

    imageПо мотивам борьбы с проблемой отображения в консоли WSUS некорректно клонированных клиентов, наткнулся на интересную заметку - ShS's Blog - Скрипт для удаленного сброса клиента службы Автоматического обновления. Представленный в этой статье скрипт был взят за основу и несколько переработан. В частности основные переменные были вынесены в отдельный блок, исключено использование временного файла, добавлена обработка исключения возникающего при обращении к 64-битным клиентским ОС, добавлена обработка исключений возникающих при удалении несуществующих ключей реестра, добавлен более детальный вывод хода выполнения скрипта на консоль.

    Скрипт работает в двух режимах, в зависимости от значения переменной $ResetSusClientId. Если значение переменной $ResetSusClientId = 0 (по умолчанию), - производится только сравнение данных о компьютерах полученных из AD и WSUS с выводом информации о значении ключа реестра SusClientId по всем проблемным клиентам. Если значение переменной $ResetSusClientId = 1, производится попытка сброса идентификационной информации клиента WU с последующей его перерегистрацией на сервере WSUS.

    ###############################################################
    # Требования: Powershell 2.0, WSUS API (Добавляется в систему при установке консоли WSUS) 
    #
    Write-Host  'Loading WSUS API...' -ForegroundColor Green
    [reflection.assembly]::LoadWithPartialName('Microsoft.UpdateServices.Administration') 
    Write-Host ''
    #
    # Блок переменных 
    # $WUSrvName – Имя сервера WSUS
    # $WUSrvPort – Порт подключения к серверу WSUS
    # $WUSrvHTTPS – Признак использования шифрования при подключении к серверу WSUS ($true или $false)
    # $ADSearchOU – ADSI путь к контейнеру с доменными учетными записями пользователей (в формате LDAP://distinguishedName)
    # $ADSearchFilter - Фильтр поиска объектов в AD (действующие учетные записи компьютеров)
    # $ResetSusClientId – Признак необходимости форсированной смены идентификатора SusClientId у отсутствующих на WSUS клиентов (1 или 0) 
    #
    $WUSrvName = 'KOM-AD01-SRV-WSUS'
    $WUSrvPort = 8530
    $WUSrvHTTPS = $false
    $ADSearchOU = 'LDAP://OU=Domain Computers,DC=mydom,DC=com'
    $ADSearchFilter = '(&(objectCategory=computer)(!userAccountControl:1.2.840.113556.1.4.803:=2))'
    $ResetSusClientId = 0
    #
    # Получаем список всех компьютеров зарегистрированных на WSUS-сервере: 
    Write-Host  'Getting WU clients data from Server' $WUSrvName 'on port' $WUSrvPort '...' -ForegroundColor Green
    $WSUS = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($WUSrvName, $WUSrvHTTPS, $WUSrvPort)
    $WSUScomps = $WSUS.GetComputerTargets() 
    $WSUSCompNames = $WSUScomps | ForEach { $_.FullDomainName.ToUpper() } 
    #
    # Получаем список учетных записей компьютеров из Active Directory: 
    Write-Host  'Getting AD computers from OU' $ADSearchOU '...' -ForegroundColor Green
    $ADcomps = (New-Object System.DirectoryServices.DirectorySearcher([ADSI]$ADSearchOU, $ADSearchFilter)).findAll() 
    $ADCompNames = $ADcomps | ForEach {$_.GetDirectoryEntry().dNSHostName.ToString().ToUpper()} 
    #
    # Получаем имена компьютеров, которые есть в Active Directory, но отсутствуют в WSUS:
    Write-Host 'Matching...' -ForegroundColor Green
    $NoWSUSCompNames = $ADCompNames | Where { $WSUSCompNames -notcontains $_ } | Sort-Object
    #
    # Блок смены идентификатора SusClientId 
    If ($NoWSUSCompNames.Count -eq $null) 
    {Write-Host 'Good. No differences.' -ForegroundColor Green}
    Else
    {
    Write-Host 'Found problem computers...' -ForegroundColor DarkRed
    Write-Host ''
    ForEach ($PC in $NoWSUSCompNames)
    {
    $Ping = New-Object System.Net.NetworkInformation.Ping
    Trap {Write-Host $PC 'can not ping' -ForegroundColor DarkRed; continue}
    If ($Ping.send($PC).Status -eq 'Success' ) {
    Write-Host $PC 'available' 
    #
    # Для того чтобы данный метод обращения к удалённому реестру успешно отработал на 64 битных системах скрипт должен запускаться в 64 PS
    # Пример проверки битности - http://poshcode.org/2027
    $is64 = [bool](gwmi win32_operatingsystem -computer $PC | ?{$_.caption -like '*x64*' -or $_.OSArchitecture -eq '64-bit'})
    $isShell32 = [bool]((Get-Process -Id $PID | ?{$_.path -like '*SysWOW64*'}) -or !([IntPtr]::Size -eq 8))
    If ($is64 -and $isShell32)
    {Write-Warning 'Unable to open registry keys because PC is running an x64 OS. Script must be run from a PowerShell x64 shell' }
    Else
    {
    $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $PC)  
    $RegKey= $Reg.OpenSubKey('SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate',$true)  
    $RegKeyValue1 = $RegKey.GetValue('SusClientId')
    #Trap {Write-Host $PC 'can not get registry key value' -ForegroundColor DarkRed; continue}
    Write-Host 'current SusClientId -' $RegKeyValue1
    If ($ResetSusClientId -eq 1) 
    {
    Write-Host 'attempt to reset SusClientId...'
    #
    # Останавливаем на удаленном компьютере службу Windows Update
    Write-Host 'stop Windows Update service (wuauserv)...'
    [System.Reflection.Assembly]::LoadWithPartialName('system.serviceprocess')
    $wuauserv=New-Object System.ServiceProcess.ServiceController('wuauserv',$PC)
    $Stopped=$true
    If ($wuauserv.Status -ne 'Stopped') {
                Try {
                            $wuauserv.Stop()
                            $wuauserv.WaitForStatus('Stopped',(new-timespan -seconds 10))
                            }
                Catch {
                            Write-Warning 'can not stop Windows Update service (wuauserv).'
                            $Stopped=$false
                            }
    }
    #
    # Удаляем идентификационные ключи клиента Windows Update из реестра, предварительно проверив их наличие  
    If ($Stopped) {
                Write-Host 'delete Windows Update registry keys...'
                If($RegKeyValue1 -ne $null){$RegKey.DeleteValue('SusClientId')}
                $RegKeyValue2 = $RegKey.GetValue('SusClientIdValidation')
                If($RegKeyValue2 -ne $null){$RegKey.DeleteValue('SusClientIdValidation')}
                $RegKeyValue3 = $RegKey.GetValue('PingID')
                If($RegKeyValue3 -ne $null){$RegKey.DeleteValue('PingID')}
                $RegKeyValue4 = $RegKey.GetValue('AccountDomainSid')
                If($RegKeyValue4 -ne $null){$RegKey.DeleteValue('AccountDomainSid')}
                $Started=$true 
                }
    #
    # Запускаем на удаленном компьютере службу Windows Update
    Write-Host 'start Windows Update service (wuauserv)...'
    Try {
                $wuauserv.Start()
                $wuauserv.WaitForStatus('Running',(new-timespan -seconds 15))
                }
    Catch {
                Write-Warning 'can not start Windows Update service (wuauserv).'
                $Started=$false
                }
    #
    # Запускаем процедуру перерегистрации клиента Windows Update на сервере WSUS
    If ($Started) {
                Start-Sleep -Seconds 5
                Write-Host 'reset authorization of WU client...'
                $RemoteProcess=([wmiclass]"\$PCrootcimv2:Win32_Process").create('cmd /c wuauclt /resetauthorization /detectnow')
                Write-Host "running return code - $($RemoteProcess.ReturnValue), process ID - $($RemoteProcess.ProcessId)"
                }
    }
    }
    }
    Else 
    { 
    Write-Host $PC 'not available' -ForegroundColor DarkRed }
    Write-Host ''
    }                                 
    }
  • WSUS – Проблемы с клонированными клиентами с дублирующимися SusClientId

    WSUSПри вводе в эксплуатацию партии новых рабочих станций HP с предустановленной ОС Windows 7 Pro OEM столкнулись с ситуацией, когда новые клиентские компьютеры успешно обновлялись с локального сервера WSUS, но при этом не появлялись на консоли WSUS. Вернее сказать, на консоли отображался лишь один новый компьютер, который последним обратился на WSUS. Изучив WindowsUpdate.log на нескольких таких клиентских компьютерах, стало очевидно, что каждый из них использует один и тот же SusClientId, что и приводит к цикличному переписыванию на WSUS сведений о новых клиентах.

    Читать далее...

  • PowerShell – Поиск пользователей домена с устаревшими паролями

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

    Для этой задачи как отправную точку я использовал PS-скрипт User Counting and Password Age Checking с блога Steve Tibbetts, несколько переработав его. В частности была убрана ненужная мне в данной ситуации зависимость от командлетов Quest, добавлена возможность управления выводом отключенных учетных записей, изменён вывод  в удобоваримый вид с сортировкой по дате установки пароля, добавлена возможность установки признака смены пароля для учетных записей с «прокисшими» паролями. Вот что получилось:

    # Блок переменных

    # $LDAPPath - ADSI путь к контейнеру с доменными учетными записями пользователей (в формате LDAP://distinguishedName)

    # $CountDisabledUsers - Признак вывода сведений об отключенных учетных записях (1 или 0)

    # $PWAgeDaysLimit - Максимально возможный период действия пароля в днях

    # $PWDMustChange - Признак необходимости форсированной установки атрибута требующего смену пароля (1 или 0)

    #

    $LDAPPath = 'LDAP://OU=Domain Users,DC=mydom,DC=com'

    $CountDisabledUsers = 0

    $PWAgeDaysLimit = 90

    $PWDMustChange = 0

    #

    # Блок поиска

    #

    $RootDomainOU = [ADSI]$LDAPPath

    $Searcher = New-Object System.DirectoryServices.DirectorySearcher($RootDomainOU)

    $Filter = '(objectCategory=person)(objectClass=user)'

    If ($CountDisabledUsers -eq 0) { $Filter = $Filter + '(!(userAccountControl:1.2.840.113556.1.4.803:=2))' }

    $Filter = '(&' + $Filter + ')'

    $Searcher.Filter = $Filter

    $Searcher.PageSize = 5000

    [Void]$Searcher.PropertiesToLoad.Add("cn")

    [Void]$Searcher.PropertiesToLoad.Add("sAMAccountName")

    [Void]$Searcher.PropertiesToLoad.Add("pwdLastSet")

    $Users = $Searcher.findall()

    #

    # Блок основного вывода

    #

    $PWDays = (Get-Date).AddDays(-$PWAgeDaysLimit)

    $UsersOldPWD = $Users | Where-Object {[datetime]::FromFileTime(($_.properties.pwdlastset)[0]) -le $PWDays}

    $UsersOldPWD | Select `

    @{label='User Full Name';expression={$_.properties.cn}},`

    @{label='sAMAccountName';expression={$_.properties.samaccountname}},`

    @{label='Last Password Set';expression={[datetime]::FromFileTime(($_.properties.pwdlastset)[0])}}`

    | Sort -Property 'Last Password Set'`

    | Format-Table –AutoSize

     

    Write-Host '---------------------------------------------------'

    write-host 'Total user accounts in OU: ' $Users.Count

    write-host 'Users with passwords not changed in' $PWAgeDaysLimit 'days: ' $UsersOldPWD.Count

    Write-Host '---------------------------------------------------'

    #

    # Блок смены атрибута учетных записей

    #

    If ($PWDMustChange -eq 1) {

    Write-Host 'Set for users with old password - Change PWD at next Logon'

    If ($UsersOldPWD.Count -eq $null)

    { Write-Host 'Ops...No account needs to be changed.'}

    Else

    {

                ForEach ($User in $UsersOldPWD)

                {

                Write-Host 'Modify user:' $User.Properties.cn

                $Account=[ADSI]$User.Path

                $Account.put("pwdLastSet", 0)

                $Account.setinfo()

                }    

    }

    Write-Host '---------------------------------------------------'

    }

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

    image

  • Exchange Server 2007 – Включение почтовых ящиков для списка пользователей из файла

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

    В нашем примере в качестве используемых значений будут имя пользователя в домене в формате DOMAINUser и алиас для создаваемого почтового ящика к этому имени пользователя. В обычном текстовом редакторе файл будет выглядеть так:

    DomainUser,mailAlias
    MYDOMivanov-ip,I.Ivanov
    MYDOMpetrov-sa,S.Petrov
    MYDOMsidorov-dg,D.Sidorov

    Чтобы убедиться в том, что PowerShell  действительно может разобрать наш файл по значениям выполним команду:

    Import-CSV C:Users.csv

    Результат вывода должен быть таким:

    image

    Непосредственно для импорта содержимого файла и включения на основе этих данных почтовых ящиков выполним:

    $DBId =  'MailboxServerStorageGroupDataBase'

    Import-CSV C:Users.csv | ForEach-Object { Enable-Mailbox -Identity $_.DomainUser -Alias $_.mailAlias –Database $DBId } | Get-Mailbox | Select Alias,WindowsEmailAddress