Скопіюйте та вставте цей зразок сценарію та змініть його за потреби для свого середовища:
<# . ПІДСУМОК Сценарій розгортання GPO для колекції подій безпечного завантаження Створення та зв'язує об'єкт групової політики для розгортання сценарію колекції як запланованого завдання
.DESCRIPTION Цей сценарій автоматизує розгортання колекції подій безпечного завантаження за допомогою Групова політика.Створюється об'єкт групової мережі з: – заплановане завдання, яке щоденно запускає сценарій колекції; - Належні дозволи на запис до центральної спільної - Фільтри WMI для націлювання певних версій ОС
.PARAMETER GPOName Ім'я нового об'єкту групової замовлення
.PARAMETER DomainName FQDN цільового домену
.PARAMETER OUPath Відмітне ім'я підрозділу для зв'язування об'єктної об'єктної роботи.Приймає кілька OUs як масив. Не потрібно, якщо вказано параметр -AutoDetectOU.
.PARAMETER AutoDetectOU Перейдіть до інтерактивного списку та виберіть OUs зі служби Active Directory.Якщо вказано, –OUPath необов'язковий.
.PARAMETER CollectionSharePath UNC-шлях, у якому зберігатимуться результати колекції
.PARAMETER ScriptSourcePath Шлях, у якому зберігається сценарій колекції (буде скопійовано до SYSVOL)
.PARAMETER RandomDelayHours Кількість годин для випадкового поширення виконання сценарію в кінцевих точках.Це запобігає одночасному запису на спільний доступ на всіх комп'ютерах.За замовчуванням: 4 години. Припустимий діапазон: 1-24 години. Рекомендовані значення: - 1-10K-пристрої: 4 години (за замовчуванням) - 10K-50K пристроїв: 8 годин - 50K+ пристроїв: 12-24 години
.EXAMPLE .\Deploy-GPO-SecureBootCollection.ps1 -DomainName "contoso.com" -OUPath "OU=Workstations,DC=contoso,DC=com"
.EXAMPLE .\Deploy-GPO-SecureBootCollection.ps1 -DomainName "contoso.com" -OUPath "OU=Workstations,DC=contoso,DC=com" -RandomDelayHours 8
.EXAMPLE .\Deploy-GPO-SecureBootCollection.ps1 -DomainName "contoso.com" -AutoDetectOU Список усіх OUs у домені та запит на вибір.
.EXAMPLE .\Deploy-GPO-SecureBootCollection.ps1 -DomainName "contoso.com" -OUPath @("OU=Workstations,DC=contoso,DC=com", "OU=Laptops,DC=contoso,DC=com") Зв'язує GPO з кількома OUs в одному запуску.
.NOTES Потрібен модуль Active Directory PowerShell, модуль Групова політика Має бути запущено з правами на Admin домену або делегованими правами на створення об'єктів групових викликів #>
[CmdletBinding()] param( [Parameter(Mandatory = $false)] [string]$GPOName = "SecureBoot-EventCollection", [Parameter(Mandatory = $false)] [string]$DomainName, [Parameter(Mandatory = $false)] [string[]]$OUPath, [Parameter(Mandatory = $false)] [switch]$AutoDetectOU, [Parameter(Mandatory = $false)] [string]$CollectionSharePath = "\\$DomainName\NETLOGON\SecureBootLogs", [Parameter(Mandatory = $false)] [string]$ScriptSourcePath = ".\Detect-SecureBootCertUpdateStatus.ps1", [Parameter(Mandatory = $false)] [ValidateSet("Daily", "Weekly", "AtStartup")] [string]$Schedule = "Щоденно", [Parameter(Mandatory = $false)] [string]$ScheduleTime = "14:00", [Parameter(Mandatory = $false)] [Перевірити рангу(1, 24)] [int]$RandomDelayHours = 4 )
#Requires -Modules ActiveDirectory, GroupPolicy #Requires версії 5.1
$ErrorActionPreference = "Stop" $DownloadUrl = "https://aka.ms/getsecureboot" $DownloadSubPage = "Зразки розгортання та моніторингу"
# ============================================================================ # ПЕРЕВІРКА ЗАЛЕЖНОСТІ # ============================================================================
function Test-ScriptDependencies { param( [Parameter(Mandatory = $true)] [string]$ScriptDirectory, [Parameter(Mandatory = $true)] [string[]]$RequiredScripts ) $missingScripts = @() foreach ($script in $RequiredScripts) { $scriptPath = Join-Path $ScriptDirectory $script якщо (-not (test-path $scriptPath)) { $missingScripts += $script } (}) } (}) якщо ($missingScripts.Count -gt 0) { Write-Host "" Write-Host ("=" * 70) -ForegroundColor Red Write-Host "ВІДСУТНІ ЗАЛЕЖНОСТІ" - Червоний колір переднього плану Write-Host ("=" * 70) - Червоний колір переднього плану Write-Host "" Write-Host "Не знайдено такі необхідні сценарії:" -ForegroundColor Yellow foreach ($script in $missingScripts) { Write-Host " - $script" -ForegroundColor White } (}) Write-Host "" Write-Host "Завантажте останні сценарії з:" -ForegroundColor Cyan Write-Host " URL-адреса: $DownloadUrl" -ForegroundColor White Write-Host " Перейти до: "$DownloadSubPage"" -ForegroundColor White Write-Host "" Write-Host "Видобути всі сценарії до одного каталогу та запустити знову". -ForegroundColor Yellow Write-Host "" повернути $false } (}) повернути $true }
# The Detect script is required - it gets deployed to endpoints via GPO $requiredScripts = @( "Detect-SecureBootCertUpdateStatus.ps1" )
if (-not (Test-ScriptDependencies -ScriptDirectory $PSScriptRoot -RequiredScripts $requiredScripts)) { вихід 1 }
# ============================================================================ # АВТОВИЯВИЗНАЧЕННЯ ІМЕНІ ДОМЕНУ # ============================================================================
if (-not $DomainName) { $DomainName = $env:USERDNSDOMAIN якщо (-не $DomainName) { # Спробуйте отримати з модуля AD спробуйте { Import-Module ActiveDirectory – зупинка дії помилки $DomainName = (Get-ADDomain). DNSRoot } зловити { Write-Host "ПОМИЛКА: не вдалося автоматично виявити ім'я домену". -ForegroundColor Red Write-Host "Укажіть параметр -DomainName". -ForegroundColor Yellow Write-Host "" Write-Host "Приклад:" -ForegroundColor Gray Write-Host " .\Deploy-GPO-SecureBootCollection.ps1 -DomainName contoso.com -AutoDetectOU" -ForegroundColor White вихід 1 } (}) } (}) Write-Host "Автоматично виявлений домен: $DomainName" -ForegroundColor Green }
# Set CollectionSharePath default if not explicitly provided якщо (-не $PSBoundParameters.ContainsKey('CollectionSharePath')) { $CollectionSharePath = "\\$DomainName\NETLOGON\SecureBootLogs" }
Write-Host "============================================" -ForegroundColor Cyan Write-Host "Secure Boot Collection - GPO Deployment" -ForegroundColor Cyan Write-Host "============================================" -ForegroundColor Cyan
# Validate prerequisites Write-Host "'n[1/6] Перевірка передумов..." -ForegroundColor Yellow
if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) { throw "Модуль ActiveDirectory не знайдено. Інсталюйте інструменти RSAT." }
if (-not (Get-Module -ListAvailable -Name GroupPolicy)) { throw "Модуль GroupPolicy не знайдено. Інсталюйте інструменти RSAT." }
Import-Module ActiveDirectory Import-Module Групова політика
# Validate domain connectivity спробуйте { $domain = Get-ADDomain -Server $DomainName Write-Host " Підключено до домену: $($domain. DNSRoot)" -ForegroundColor Green } зловити { throw "Не вдалося підключитися до домену: $DomainName. Помилка: $_" }
# Handle OU selection якщо ($AutoDetectOU) { Write-Host "'n Discovering OUs in domain..." -ForegroundColor Cyan $allOUs = Get-ADOrganizationalUnit -Filter * -Server $DomainName | Sort-Object Відмітне ім'я | Select-Object @{N="Індекс"; E={0}}, ім'я, відмітна назва # Призначення індексів для ($i = 0; $i -lt $allOUs.Count; $i++) { $allOUs[$i]. Індекс = $i + 1 } (}) Write-Host "'n Available OUs:" -ForegroundColor Yellow Write-Host " ---------------------------------------------------------------------" -ForegroundColor DarkGray $allOUs | ForEach-Object { Write-Host (" {0,3}) {1}" -f $_. Індекс, $_. DistinguishedName) – білий колір переднього плану } (}) Write-Host " ---------------------------------------------------------------------" -ForegroundColor DarkGray Write-Host " Порада. Введіть числа, розділені комами, щоб вибрати кілька OUs (наприклад, 1,3,5)" -ForegroundColor DarkGray Write-Host " Enter "A", щоб вибрати ALL OUs" -ForegroundColor DarkGray Write-Host "" $selection = Read-Host " Виберіть OU(и), щоб зв'язати GPO" якщо ($selection -eq 'A' -або $selection -eq 'a') { $OUPath = $allOUs.DistinguishedName Write-Host " Selected ALL $($OUPath.Count) OUs" -ForegroundColor Green } інакше { $indices = $selection -split "", | ForEach-Object { [int]$_. Trim() } $OUPath = @() foreach ($idx in $indices) { $selected = $allOUs | Where-Object { $_. Індекс –eq $idx } якщо ($selected) { $OUPath += $selected. Відмітна назва } інакше { Write-Warning "Неприпустимий індекс: $idx - пропуск" } (}) } (}) } (}) якщо ($OUPath.Count -eq 0) { throw "No OUs selected. Перервано". } (}) Write-Host "'n Selected $($OUPath.Count) OU(s):" -ForegroundColor Green $OUPath | ForEach-Object { Write-Host " - $_" -ForegroundColor Gray } } elseif (-not $OUPath -або $OUPath.Count -eq 0) { throw "Потрібно вказати -OUPath або -AutoDetectOU." } інакше { # Перевірка наявності кожного підрозділу foreach ($path in $OUPath) { спробуйте { $ou = Get-ADOrganizationalUnit -Identity $path -Server $DomainName Write-Host " Цільовий підрозділу знайдено: $($ou. Name)" -ForegroundColor Green } зловити { throw "OU не знайдено: $path" } (}) } (}) }
# Validate source script exists якщо (-not (test-path $ScriptSourcePath)) { throw "Сценарій колекції не знайдено: $ScriptSourcePath" }
# Step 2: Create collection share structure Write-Host "'n[2/6] Налаштування спільної колекції..." -ForegroundColor Yellow
$sysvolScriptPath = "\\$DomainName\SYSVOL\$DomainName\Scripts\SecureBootCollection"
# Create SYSVOL script folder якщо (-not (test-path $sysvolScriptPath)) { New-Item -ItemType Directory – шлях $sysvolScriptPath -Force | Out-Null Write-Host " Створено папку сценаріїв SYSVOL: $sysvolScriptPath" -ForegroundColor Green }
# Copy collection script to SYSVOL $destScript = Join-Path $sysvolScriptPath "Detect-SecureBootCertUpdateStatus.ps1"
# Remove existing destination if it's a directory (fix for Copy-Item bug) якщо (тестовий $destScript -PathType контейнер) { Remove-Item $destScript -Recurse -Force }
Copy-Item -Path $ScriptSourcePath -Destination $destScript -Force Write-Host " Скопійований сценарій колекції до SYSVOL" -ForegroundColor Green
# Create a wrapper script that calls the main script with parameters $wrapperScript = @" # Secure Boot Event Collection Wrapper # Автоматично створений Deploy-GPO-SecureBootCollection.ps1
`$ErrorActionPreference = 'SilentlyContinue'
# Configuration '$CollectionShare = '$CollectionSharePath' '$ScriptPath = '$sysvolScriptPath\Detect-SecureBootCertUpdateStatus.ps1'
# Run collection with -OutputPath parameter якщо (тестовий шлях "$ScriptPath) { & '$ScriptPath -OutputPath '$CollectionShare } інакше { Write-EventLog -LogName Application -Source "SecureBootCollection" -EventId 1001 -EntryType Error -Message "Сценарій колекції не знайдено: "$ScriptPath" } (}) " @
$wrapperPath = Join-Path $sysvolScriptPath "Run-SecureBootCollection.ps1" $wrapperScript | Out-File -FilePath $wrapperPath -Encoding UTF8 -Force Write-Host " Created wrapper script" -ForegroundColor Green
# Create collection share (if on a file server) Write-Host " Шлях спільного доступу до колекції: $CollectionSharePath" -ForegroundColor Cyan Write-Host " ПРИМІТКА. Переконайтеся, що ця спільна ресурс існує з доступом до запису "Доменні комп'ютери" -ForegroundColor Yellow
# Step 3: Create the GPO Write-Host "'n[3/6] Створення об'єкта Групова політика..." -ForegroundColor Yellow
# Check if GPO already exists $existingGPO = Get-GPO - Name $GPOName -Domain $DomainName -ErrorAction SilentlyContinue
if ($existingGPO) { Write-Host " GPO "$GPOName" уже існує. Триває оновлення..." – жовтий колір переднього плану $gpo = $existingGPO } інакше { $gpo = New-GPO - Name $GPOName -Domain $DomainName -Comment "Deploys Secure Boot event script to endpoints" Write-Host " Створено групову фразу: $GPOName" -ForegroundColor Green }
# Step 4: Configure Scheduled Task via GPO Preferences Write-Host "'n[4/6] Настроювання запланованого завдання..." -ForegroundColor Yellow
# Build the scheduled task XML # RandomDelay поширюється на кінцеві точки, щоб запобігти перевантаженню сервера Write-Host " Випадкова затримка: $RandomDelayHours годин (поширюється навантаження по флоту)" -ForegroundColor Cyan
$taskTrigger = switch ($Schedule) { "Щоденно" { @" <>>"< календарів" <startBoundary>2024-01-01T${ScheduleTime}:00</StartBoundary> <увімкнуто>true</Enabled> <ScheduleByDay> <днівInterval>1</DaysInterval> </ScheduleByDay> <RandomDelay>PT${RandomDelayHours}H</RandomDelay> </CalendarTrigger> "@ } (}) "Щотижнево" { @" <>>"< календарів" <Початкова>2024-01-01T${ScheduleTime}:00</StartBoundary> <увімкнуто>true</Enabled> <> ScheduleByWeek <тижнівInterval>1</WeeksInterval> <>"День тижня" <середу /> </DaysOfWeek> </ScheduleByWeek> <RandomDelay>PT${RandomDelayHours}H</RandomDelay> </CalendarTrigger> "@ } (}) "AtStartup" { # Для тригерів запуску використовуйте функцію Delay (Затримка), щоб додати випадковий час початку. # Кожен комп'ютер запускається між 5 і (5 + RandomDelayHours *60) хвилин після завантаження $maxDelayMinutes = 5 + ($RandomDelayHours * 60) @" <>BootTrigger <увімкнуто>true</Enabled> <затримка>PT5M</Затримка> <RandomDelay>PT${RandomDelayHours}H</RandomDelay> </BootTrigger> "@ } (}) }
$scheduledTaskXML = @" <?xml version="1.0" encoding="UTF-16"?> <Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task"> <RegistrationInfo> <Опис>збирає дані події безпечного завантаження для корпоративного перепису</Description> <автор><корпоративної безпеки /автор> </RegistrationInfo> тригери <> $taskTrigger </Triggers> >принципалів < <principal id="Author"> <ідентифікатор користувача>S-1-5-18</UserId> <runLevel>HighestAvailable</RunLevel> </>принципала </Principals> >настройок < <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries> <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries> <AllowHardTerminate>true</AllowHardTerminate> <початокВиявний>true</StartWhenAvailable> <RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable> <>IdleSettings <StopOnIdleEnd>false</StopOnIdleEnd> <RestartOnIdle>false</RestartOnIdle> </IdleSettings> <AllowStartOnDemand>true</AllowStartOnDemand> <Увімкнуто>true</Enabled> <приховані>false</Hidden> <RunOnlyIfIdle>false</RunOnlyIfIdle> <ЗаборонитиStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession> <UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine> <WakeToRun>false</WakeToRun> <ExecutionTimeLimit>PT1H</ExecutionTimeLimit> <пріоритет>7</Priority> </Settings> <actions Context="Author"> <Exec> <команд>powershell.exe</Command> <аргументи>-NoProfile -ExecutionPolicy Bypass -File "$wrapperPath"</Arguments> </Exec> </Actions> </> завдань " @
# Save task XML to SYSVOL for reference/backup $taskXmlPath = Join-Path $sysvolScriptPath "SecureBootCollection-Task.xml" $scheduledTaskXML | Out-File -FilePath $taskXmlPath -Encoding Юнікод -Force Write-Host " Saved scheduled task XML to SYSVOL (backup)" -ForegroundColor Green
# Inject scheduled task into GPO Preferences Write-Host "Ін'єкція запланованого завдання в GPO Preferences..." -ForegroundColor Cyan
$gpoId = $gpo.Id.ToString() $gpoPrefPath = "\\$DomainName\SYSVOL\$DomainName\Policies\{$gpoId}\Machine\Preferences\ScheduledTasks"
# Create Preferences folder structure if (-not (test-path $gpoPrefPath)) { New-Item -ItemType Directory – шлях $gpoPrefPath -Force | Out-Null }
# Generate unique GUID for the task $taskGuid = [GUID]::NewGuid(). ToString("B"). ToUpper()
# Build GPO Preferences ScheduledTasks.xml format # Це відрізняється від стандартного XML планувальника завдань – це формат GPP $gppScheduledTasksXml = @" <?xml version="1.0" encoding="utf-8"?> <scheduledTasks clsid="{CC63F200-7309-4ba0-B154-A71CD118DBCC}"> <TaskV2 clsid="{D8896631-B747-47a7-84A6-C155337F3BC8}" name="SecureBoot-EventCollection" image="0" changed="0"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')» uid="$taskGuid" userContext="0" removePolicy="0"> <Properties action="C" name="SecureBoot-EventCollection" runAs="NT AUTHORITY\System" logonType="S4U"> <версія завдання="1.3"> <RegistrationInfo> <автор><корпоративної безпеки /Автор> <Опис>збирає стан сертифіката безпечного завантаження для моніторингу відповідності корпоративному</Description> </RegistrationInfo> >принципалів < <principal id="Author"> <UserId>NT AUTHORITY\System</UserId> <LogonType>S4U</LogonType> <runLevel>HighestAvailable</RunLevel> </principal> </Principals> >настройок < <>idleSettings <тривалість>PT10M</тривалість> <waitTimeout>PT1H</WaitTimeout> <StopOnIdleEnd>false</StopOnIdleEnd> <RestartOnIdle>false</RestartOnIdle> </IdleSettings> <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries> <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries> <AllowHardTerminate>true</AllowHardTerminate> <початокУвімніть,>true</StartWhenAvailable> <RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable> <AllowStartOnDemand>true</AllowStartOnDemand> <увімкнуто>true</Enabled> <прихований>false</Hidden> <RunOnlyIfIdle>false</RunOnlyIfIdle> <WakeToRun>false</WakeToRun> <executionTimeLimit>PT1H</ExecutionTimeLimit> <пріоритет>7</Priority> </Settings> тригери <> $taskTrigger </Triggers> <actions Context="Author"> <Exec> >powershell.exe<команд </Command> <аргументи>-NoProfile -ExecutionPolicy Bypass -File "$wrapperPath"</Arguments> </Exec> </Actions> </> завдань </Properties> </TaskV2> </ScheduledTasks> " @
# Write GPP ScheduledTasks.xml to GPO $gppXmlPath = Join-Path $gpoPrefPath "ScheduledTasks.xml" $gppScheduledTasksXml | Out-File -FilePath $gppXmlPath -Encoding UTF8 -Force Write-Host " [OK] Заплановане завдання вводиться в GPO" -ForegroundColor Green Write-Host " Розклад завдань: $Schedule на $ScheduleTime з випадковою затримкою $RandomDelayHours години" -ForegroundColor Gray
# Step 5: Link GPO to OU(s) Write-Host "'n[5/6] Зв'язування GPO з OU(и)..." -ForegroundColor Yellow
$linkedCount = 0 $skippedCount = 0
foreach ($targetOU in $OUPath) { $existingLink = Get-GPInheritance -Target $targetOU -Domain $DomainName | Select-Object -ExpandProperty GpoLinks | Where-Object { $_. DisplayName –eq $GPOName }
if (-not $existingLink) { New-GPLink -Name $GPOName -Target $targetOU -Domain $DomainName -LinkEnabled Так | Out-Null Write-Host " [OK] Пов'язано з: $targetOU" -ForegroundColor Green $linkedCount++ } інакше { Write-Host " – уже зв'язано: $targetOU" -ForegroundColor Yellow $skippedCount++ } (}) }
Write-Host "`n Summary: $linkedCount new links, $skippedCount already existed" -ForegroundColor Cyan
# Step 6: Create WMI Filter (optional - for Windows 10/11 only) Write-Host "'n[6/6] Створення фільтра WMI..." -ForegroundColor Yellow
$wmiFilterName = "Windows 10 and 11 Workstations" $wmiQuery = "SELECT * FROM Win32_OperatingSystem WHERE VERSION LIKE "10.%" AND ProductType = "1""
Write-Host @" [ПРИМІТКА] НЕОБОВ'ЯЗКОВО: Створення фільтра WMI у консолі керування груповими політиками (GPMC) Ім'я фільтра: $wmiFilterName Запит: $wmiQuery Це фільтрує об'єкт групової безпеки, який застосовуватиметься лише до робочих станцій Windows 10/11.
"@ -ForegroundColor Yellow
# Summary Write-Host "'n============================================" -ForegroundColor Cyan Write-Host "РОЗГОРТАННЯ ЗАВЕРШЕНО" - Зелений колір переднього плану Write-Host "============================================" -ForegroundColor Cyan Write-Host @"
Summary: - Ім'я об'єктної об'єктної об'єкт $GPOName ної об'єкт - Цільовий підрозділу: $OUPath - Спільний доступ до колекції: $CollectionSharePath - Розташування сценарію: $sysvolScriptPath - розклад: $Schedule за адресою $ScheduleTime
Next Steps: 1. Створіть спільний доступ до колекції з відповідними дозволами: - Спільний доступ: $CollectionSharePath - Дозволи: доменні комп'ютери (записування), адміністратори домену (повний)
2. Complete the scheduled task configuration in GPMC (see instructions above)
3. Run 'gpupdate /force' on a test machine to verify deployment
4. Monitor collection results in: $CollectionSharePath
5. Run aggregation script to generate reports: .\Aggregate-SecureBootData.ps1 -InputPath "$CollectionSharePath"
"@ -ForegroundColor White