Copiez et collez cet exemple de script et modifiez-le si nécessaire pour votre environnement :
<# . SYNOPSIS Script de déploiement d’objet de stratégie de groupe pour la collecte d’événements de démarrage sécurisé Crée et lie un objet de stratégie de groupe pour déployer le script de collection en tant que tâche planifiée
.DESCRIPTION Ce script automatise le déploiement de la collecte d’événements de démarrage sécurisé via stratégie de groupe.Il crée un objet de stratégie de groupe avec : - Tâche planifiée qui exécute le script de collection quotidiennement - Autorisations appropriées pour l’écriture dans le partage central - Filtres WMI pour cibler des versions de système d’exploitation spécifiques
.PARAMETER GPOName Nom du nouvel objet de stratégie de groupe
.PARAMETER DomainName Nom de domaine complet du domaine cible
.PARAMETER OUPath Nom unique de l’unité d’organisation à laquelle lier l’objet de stratégie de groupe.Accepte plusieurs unités d’organisation en tant que tableau. Non obligatoire si -AutoDetectOU est spécifié.
.PARAMETER AutoDetectOU Basculez vers la liste interactive et sélectionnez unités d’organisation à partir d’Active Directory.Quand il est spécifié, -OUPath est facultatif.
.PARAMETER CollectionSharePath Chemin d’accès UNC où les résultats de la collection seront stockés
.PARAMETER ScriptSourcePath Chemin d’accès où le script de collection est stocké (sera copié dans SYSVOL)
.PARAMETER RandomDelayHours Nombre d’heures pour répartir de manière aléatoire l’exécution de script entre les points de terminaison.Cela empêche toutes les machines d’écrire simultanément dans le partage.Valeur par défaut : 4 heures. Plage valide : 1 à 24 heures. Valeurs recommandées : - 1-10 000 appareils : 4 heures (par défaut) - 10 000 à 50 000 appareils : 8 heures - Plus de 50 000 appareils : 12 à 24 heures
.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 Répertorie toutes les unités d’organisation dans le domaine et invite à la sélection.
.EXAMPLE .\Deploy-GPO-SecureBootCollection.ps1 -DomainName « contoso.com » -OUPath @(« OU=Workstations,DC=contoso,DC=com », « OU=Laptops,DC=contoso,DC=com ») Lie l’objet de stratégie de groupe à plusieurs unités d’organisation en une seule exécution.
.NOTES Nécessite : module Active Directory PowerShell, module stratégie de groupe Doit être exécuté avec des droits de Administration de domaine ou de création d’objets de stratégie de groupe délégués #>
[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 = « Daily », [Parameter(Mandatory = $false)] [string]$ScheduleTime = « 14:00 », [Parameter(Mandatory = $false)] [ValidateRange(1, 24)] [int]$RandomDelayHours = 4 )
#Requires -Modules ActiveDirectory, GroupPolicy #Requires -Version 5.1
$ErrorActionPreference = "Stop" $DownloadUrl = « https://aka.ms/getsecureboot » $DownloadSubPage = « Exemples de déploiement et de surveillance »
# ============================================================================ # VALIDATION DES DÉPENDANCES # ============================================================================
function Test-ScriptDependencies { param( [Parameter(Mandatory = $true)] [string]$ScriptDirectory, [Parameter(Mandatory = $true)] [string[]]$RequiredScripts ) $missingScripts = @() foreach ($script dans $RequiredScripts) { $scriptPath = Join-Path $ScriptDirectory $script if (-not (Test-Path $scriptPath)) { $missingScripts += $script } } if ($missingScripts.Count -gt 0) { Write-Host « » Write-Host (« = » * 70) -ForegroundColor Red Write-Host « DÉPENDANCES MANQUANTES » -ForegroundColor Red Write-Host (« = » * 70) -ForegroundColor Red Write-Host « » Write-Host « Les scripts requis suivants sont introuvables » -ForegroundColor Yellow foreach ($script dans $missingScripts) { Write-Host " - $script » -ForegroundColor White } Write-Host « » Write-Host « Veuillez télécharger les derniers scripts à partir de : » -ForegroundColor Cyan Write-Host " URL : $DownloadUrl » -ForegroundColor White Write-Host « Accéder à : '$DownloadSubPage' » -ForegroundColor White Write-Host « » Write-Host « Extraire tous les scripts dans le même répertoire et réexécuter ». -ForegroundColor Yellow Write-Host « » $false de retour } $true de retour }
# The Detect script is required - it gets deployed to endpoints via GPO $requiredScripts = @( « Detect-SecureBootCertUpdateStatus.ps1 » )
if (-not (Test-ScriptDependencies -ScriptDirectory $PSScriptRoot -RequiredScripts $requiredScripts)) { sortie 1 }
# ============================================================================ # DÉTECTION AUTOMATIQUE DU NOM DE DOMAINE # ============================================================================
if (-not $DomainName) { $DomainName = $env :USERDNSDOMAIN if (-not $DomainName) { # Essayer d’obtenir à partir du module AD try { Import-Module ActiveDirectory -ErrorAction Stop $DomainName = (Get-ADDomain). DNSRoot } catch { Write-Host « ERREUR : Impossible de détecter automatiquement le nom de domaine ». -ForegroundColor Red Write-Host « Veuillez spécifier le paramètre -DomainName ». -ForegroundColor Yellow Write-Host « » Write-Host « Example : » -ForegroundColor Gray Write-Host " .\Deploy-GPO-SecureBootCollection.ps1 -DomainName contoso.com -AutoDetectOU » -ForegroundColor White sortie 1 } } Write-Host « Domaine détecté automatiquement : $DomainName » -ForegroundColor Vert }
# Set CollectionSharePath default if not explicitly provided if (-not $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] Validation des prérequis... -ForegroundColor Yellow
if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) { lève « Module ActiveDirectory introuvable. Installez les outils RSAT. » }
if (-not (Get-Module -ListAvailable -Name GroupPolicy)) { lève le module GroupPolicy introuvable. Installez les outils RSAT. » }
Import-Module ActiveDirectory Import-Module GroupPolicy
# Validate domain connectivity try { $domain = Get-ADDomain -Server $DomainName Write-Host " Connecté au domaine : $($domain. DNSRoot)" -ForegroundColor Vert } catch { lève « Impossible de se connecter au domaine : $DomainName. Erreur : $_" }
# Handle OU selection if ($AutoDetectOU) { Write-Host « 'n Découverte des unités d’organisation dans le domaine... » -ForegroundColor Cyan $allOUs = Get-ADOrganizationalUnit -Filter * -Server $DomainName | Sort-Object DistinguishedName | Select-Object @{N='Index' ; E={0}}, Name, DistinguishedName # Affecter des index for ($i = 0 ; $i -lt $allOUs.Count ; $i++) { $allOUs[$i]. Index = $i + 1 } Write-Host « 'n Unités d’organisation disponibles : » -ForegroundColor Yellow Write-Host " --------------------------------------------------------------------- » -ForegroundColor DarkGray $allOUs | ForEach-Object { Write-Host ( » {0,3}) {1} » -f $_. Index, $_. DistinguishedName) -ForegroundColor White } Write-Host " --------------------------------------------------------------------- » -ForegroundColor DarkGray Write-Host " Conseil : entrez des nombres séparés par des virgules pour sélectionner plusieurs unités d’organisation (par exemple, 1,3,5) " -ForegroundColor DarkGray Write-Host " Entrez 'A' pour sélectionner TOUTES les unités d’organisation » -ForegroundColor DarkGray Write-Host « » $selection = Read-Host « Sélectionner une ou plusieurs unités d’organisation pour lier l’objet de stratégie de groupe » if ($selection -eq 'A' -or $selection -eq 'a') { $OUPath = $allOUs.DistinguishedName Write-Host « Selected ALL $($OUPath.Count) OU » -ForegroundColor Vert } else { $indices = $selection -split ',' | ForEach-Object { [int]$_. Trim() } $OUPath = @() foreach ($idx dans $indices) { $selected = $allOUs | Where-Object { $_. Index -eq $idx } if ($selected) { $OUPath += $selected. Distinguishedname } else { Write-Warning « Index non valide : $idx - ignorer » } } } if ($OUPath.Count -eq 0) { lève « Aucune unités d’organisation sélectionnée. Avorter. } Write-Host « 'n Unités d’organisation $($OUPath.Count) sélectionnées) : » -ForegroundColor Vert $OUPath | ForEach-Object { Write-Host " - $_ » -ForegroundColor Gray } } elseif (-not $OUPath -or $OUPath.Count -eq 0) { lève « -OUPath ou -AutoDetectOU doit être spécifié ». } else { Nombre de validations de l’existence de chaque unité d’organisation foreach ($path dans $OUPath) { try { $ou = Get-ADOrganizationalUnit -Identity $path -Server $DomainName Write-Host « Unité d’organisation cible trouvée : $($ou. Nom)" -ForegroundColor Vert } catch { lève « Unité d’organisation introuvable : $path » } } }
# Validate source script exists if (-not (Test-Path $ScriptSourcePath)) { lève « Script de collection introuvable : $ScriptSourcePath » }
# Step 2: Create collection share structure Write-Host « 'n[2/6] Configuration du partage de collection... - ForegroundColor Yellow
$sysvolScriptPath = "\\$DomainName\SYSVOL\$DomainName\Scripts\SecureBootCollection"
# Create SYSVOL script folder if (-not (Test-Path $sysvolScriptPath)) { New-Item -ItemType Directory -Path $sysvolScriptPath -Force | Out-Null Write-Host « Dossier de script SYSVOL créé : $sysvolScriptPath » -ForegroundColor Vert }
# 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) if (Test-Path $destScript -PathType Container) { Remove-Item $destScript -Récurse -Force }
Copy-Item -Path $ScriptSourcePath -Destination $destScript -Force Write-Host « Script de collection copié dans SYSVOL » -ForegroundColor Vert
# Create a wrapper script that calls the main script with parameters $wrapperScript = @" # Wrapper de collection d’événements de démarrage sécurisé Nombre généré automatiquement par Deploy-GPO-SecureBootCollection.ps1
`$ErrorActionPreference = 'SilentlyContinue'
# Configuration '$CollectionShare = '$CollectionSharePath' '$ScriptPath = '$sysvolScriptPath\Detect-SecureBootCertUpdateStatus.ps1'
# Run collection with -OutputPath parameter if (Test-Path '$ScriptPath) { & '$ScriptPath -OutputPath '$CollectionShare } else { Write-EventLog -LogName Application -Source « SecureBootCollection » -EventId 1001 -EntryType Error -Message « Script de collection introuvable : '$ScriptPath » } " @
$wrapperPath = Join-Path $sysvolScriptPath "Run-SecureBootCollection.ps1" $wrapperScript | Out-File -FilePath $wrapperPath -Encodage UTF8 -Force Write-Host « Script wrapper créé » -ForegroundColor Vert
# Create collection share (if on a file server) Write-Host « Chemin du partage de collection : $CollectionSharePath » -ForegroundColor Cyan Write-Host « REMARQUE : Vérifier que ce partage existe avec l’accès en écriture « Ordinateurs de domaine » -ForegroundColor Yellow
# Step 3: Create the GPO Write-Host « 'n[3/6] Création d’un objet stratégie de groupe... -ForegroundColor Yellow
# Check if GPO already exists $existingGPO = Get-GPO -Name $GPOName -Domain $DomainName -ErrorAction SilentlyContinue
if ($existingGPO) { Write-Host l’objet de stratégie de groupe « $GPOName » existe déjà. Mise à jour..." -ForegroundColor Yellow $gpo = $existingGPO } else { $gpo = New-GPO -Name $GPOName -Domain $DomainName -Comment « Deploys Secure Boot event collection script to endpoints » Write-Host « Objet de stratégie de groupe créé : $GPOName » -ForegroundColor Vert }
# Step 4: Configure Scheduled Task via GPO Preferences Write-Host « 'n[4/6] Configuration de la tâche planifiée... -ForegroundColor Yellow
# Build the scheduled task XML # RandomDelay répartit l’exécution entre les points de terminaison pour éviter la surcharge du serveur Write-Host « Délai aléatoire : $RandomDelayHours heures (répartit la charge sur la flotte) » -ForegroundColor Cyan
$taskTrigger = switch ($Schedule) { « Daily » { @" <> CalendarTrigger <StartBoundary>2024-01-01T${ScheduleTime} :00</StartBoundary> <Activé>true</Enabled> <>ScheduleByDay <DaysInterval>1</DaysInterval> </ScheduleByDay> <RandomDelay>PT${RandomDelayHours}H</RandomDelay> <>/CalendarTrigger "@ } « Hebdomadaire » { @" <> CalendarTrigger <StartBoundary>2024-01-01T${ScheduleTime} :00</StartBoundary> <Activé>true</Enabled> <>ScheduleByWeek <WeeksInterval>1</WeeksInterval> <DaysOfWeek> <mercredi /> <>/DaysOfWeek </ScheduleByWeek> <RandomDelay>PT${RandomDelayHours}H</RandomDelay> <>/CalendarTrigger "@ } « AtStartup » { # Pour les déclencheurs de démarrage, utilisez Delay pour ajouter une heure de début aléatoire # Chaque machine démarre entre 5 et (5 + RandomDelayHours*60) minutes après le démarrage $maxDelayMinutes = 5 + ($RandomDelayHours * 60) @" <>BootTrigger <Activé>true</Enabled> <Retard>pt5M</Delay> <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>Collecte des données d’événement de démarrage sécurisé pour les<de recensement d’entreprise /Description> <Author>Enterprise Security</Author> <>/RegistrationInfo >déclencheurs < $taskTrigger </Triggers> >principaux < <Principal id="Author"> <UserId>S-1-5-18</UserId> <RunLevel>HighestAvailable</RunLevel> </Principal> <>/Principals >paramètres de < <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries> <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries> <AllowHardTerminate>true</AllowHardTerminate> <StartWhenAvailable>true</StartWhenAvailable> <RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable> <IdleSettings> <StopOnIdleEnd>false</StopOnIdleEnd> <RestartOnIdle>false</RestartOnIdle> <>/IdleSettings <AllowStartOnDemand>true</AllowStartOnDemand> <Activé>true</Enabled> <></Hidden> <RunOnlyIfIdle>false</RunOnlyIfIdle> <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession> <UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine> <WakeToRun>false</WakeToRun> <ExecutionTimeLimit>PT1H</ExecutionTimeLimit> priorité <>7</> de priorité >/Settings < <Actions Context="Author"> ><Exec <command>powershell.exe</Command> Arguments <>-NoProfile -ExecutionPolicy Bypass -File « $wrapperPath"</Arguments> <>/Exec </Actions> </Task> " @
# Save task XML to SYSVOL for reference/backup $taskXmlPath = Join-Path $sysvolScriptPath « SecureBootCollection-Task.xml » $scheduledTaskXML | Out-File -FilePath $taskXmlPath -Encodage Unicode -Force Write-Host « Fichier XML de tâche planifiée enregistré dans SYSVOL (sauvegarde) » -ForegroundColor Vert
# Inject scheduled task into GPO Preferences Write-Host « Injecting scheduled task into 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 -Path $gpoPrefPath -Force | Out-Null }
# Generate unique GUID for the task $taskGuid = [guid] ::NewGuid(). ToString(« B »). ToUpper()
# Build GPO Preferences ScheduledTasks.xml format # Ceci est différent du code XML standard du planificateur de tâches : il s’agit du format 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="$(Get-Date -Format 'aaaa-MM-dd HH :mm :ss') » uid="$taskGuid » userContext="0 » removePolicy="0"> <Properties action="C » name="SecureBoot-EventCollection » runAs="NT AUTHORITY\System » logonType="S4U"> <Task version="1.3"> >RegistrationInfo < <Author>Enterprise Security</Author> <Description>collecte des status de certificat de démarrage sécurisé pour la surveillance de la conformité de l’entreprise</Description> <>/RegistrationInfo >principaux < <Principal id="Author"> <UserId>NT AUTHORITY\System</UserId> <LogonType>S4U</LogonType> <RunLevel>HighestAvailable</RunLevel> <>/Principal <>/Principals >paramètres de < <>IdleSettings <Durée>PT10M</Durée> <WaitTimeout>pt1H</WaitTimeout> <StopOnIdleEnd>false</StopOnIdleEnd> <RestartOnIdle>false</RestartOnIdle> </IdleSettings> <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries> <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries> <AllowHardTerminate>true</AllowHardTerminate> <StartWhenAvailable>true</StartWhenAvailable> <RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable> <AllowStartOnDemand>true</AllowStartOnDemand> <Activé>true</Enabled> <>false</Hidden> <RunOnlyIfIdle>false</RunOnlyIfIdle> <WakeToRun>false</WakeToRun> <ExecutionTimeLimit>PT1H</ExecutionTimeLimit> Priorité <>7</Priorité> <>/Settings >déclencheurs < $taskTrigger </Triggers> <Actions Context="Author"> <>Exec <commande>powershell.exe</> de commande Arguments <>-NoProfile -ExecutionPolicy Bypass -File « $wrapperPath"</Arguments> <>/Exec </Actions> <>/Task <>/Properties <>/TaskV2 <>/ScheduledTasks " @
# Write GPP ScheduledTasks.xml to GPO $gppXmlPath = Join-Path $gpoPrefPath « ScheduledTasks.xml » $gppScheduledTasksXml | Out-File -FilePath $gppXmlPath -Encodage UTF8 -Force Write-Host « [OK] Tâche planifiée injectée dans l’objet de stratégie de groupe » -ForegroundColor Vert Write-Host « Planification des tâches : $Schedule à $ScheduleTime avec délai aléatoire de $RandomDelayHours heure » -ForegroundColor Gray
# Step 5: Link GPO to OU(s) Write-Host « 'n[5/6] Liaison de l’objet de stratégie de groupe à une ou plusieurs unités d’organisation... -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 Oui | Out-Null Write-Host " [OK] Lié à : $targetOU » -ForegroundColor Green $linkedCount++ } else { Write-Host " - Déjà lié : $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] Création d’un filtre WMI... - ForegroundColor Yellow
$wmiFilterName = "Windows 10 and 11 Workstations" $wmiQuery = 'SELECT * FROM Win32_OperatingSystem WHERE Version COMME « 10. % » ET ProductType = « 1"'
Write-Host @" [REMARQUE] FACULTATIF : Créer un filtre WMI dans la console GPMC Nom du filtre : $wmiFilterName Requête : $wmiQuery Cela filtre l’objet de stratégie de groupe pour qu’il s’applique uniquement aux stations de travail Windows 10/11.
"@ -ForegroundColor Yellow
# Summary Write-Host « 'n============================================ » -ForegroundColor Cyan Write-Host « DÉPLOIEMENT TERMINÉ » -ForegroundColor Vert Write-Host « ============================================ » -ForegroundColor Cyan Write-Host @"
Summary: - Nom de l’objet de stratégie de groupe : $GPOName - Unité d’organisation cible : $OUPath - Partage de collection : $CollectionSharePath - Emplacement du script : $sysvolScriptPath - Planification : $Schedule à $ScheduleTime
Next Steps: 1. Créez le partage de collection avec les autorisations appropriées : - Partager : $CollectionSharePath - Autorisations : Ordinateurs de domaine (écriture), Administrateurs de domaine (complet)
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