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  

​​​​​​​

Besoin d’aide ?

Vous voulez plus d’options ?

Explorez les avantages de l’abonnement, parcourez les cours de formation, découvrez comment sécuriser votre appareil, etc.