Procédure de déploiement ZopeEdit 1.1.2 via GPO#
Référence : IA.DOCS-GPO-DEPLOY-ZopeEdit-v1.0 Auteur : christophe Tourment Date : 28 mai 2026 Cible : Windows 11 Pro Méthode : GPO Startup Script (PowerShell)
1. Contexte et objectif#
1.1 Objectif#
Déployer automatiquement le package ZopeEdit-1.1.2.msi (généré via Scalable Smart Package) sur les postes Windows 11 Pro du domaine votre.commune.be via une GPO de type Startup Script.
1.2 Pourquoi un Startup Script et pas un Logon Script ?#
Type de script |
Contexte d’exécution |
Droits |
Installation MSI machine |
|---|---|---|---|
Startup Script |
|
Administrateur local |
✅ Oui |
Logon Script |
Utilisateur connecté |
Limités |
❌ Non (sauf user admin) |
L’installation d’un MSI machine-wide requiert les droits SYSTEM, donc uniquement un Startup Script est viable.
1.3 Pourquoi un script PowerShell et pas l’option “Software Installation” native de la GPO ?#
L’option Computer Configuration → Software Settings → Software Installation déploie nativement les MSI, mais :
pas de gestion fine des versions ni des codes de retour MSI
pas de log centralisé exploitable par Zabbix
diagnostic difficile en cas d’échec
pas de logique d’idempotence personnalisée
Le script PowerShell offre un contrôle complet et une journalisation détaillée.
2. Prérequis#
2.1 Infrastructure#
✅ Contrôleur de domaine
ad.votre.commune.beopérationnel✅ Partage SYSVOL accessible en lecture pour les machines du domaine
✅ GPO
{Unique ID}créée et liée à l’OU contenant les postes Windows 11 cibles
2.2 Postes clients#
Windows 11 Pro joint au domaine
votre.commune.bePowerShell 5.1 (présent par défaut sur Windows 11)
ExecutionPolicy autorisant l’exécution de scripts (voir §4)
2.3 Fichiers#
ZopeEdit-1.1.2.msi(package MSI à déployer)Deploy-ZopeEdit.ps1(script de déploiement, fourni en §3)
3. Script de déploiement PowerShell#
3.1 Emplacement#
Le script et le MSI doivent être copiés ensemble dans le dossier Startup de la GPO :
\\votre.commune.be\SYSVOL\votre.commune.be\Policies\{Unique ID}\Machine\Scripts\Startup\
├── Deploy-ZopeEdit.ps1
└── ZopeEdit-1.1.2.msi
3.2 Code du script#
Fichier : Deploy-ZopeEdit.ps1
<#
.SYNOPSIS
Déploiement du package ZopeEdit-1.1.2.msi via GPO Startup Script.
.DESCRIPTION
Script de déploiement idempotent qui :
- Vérifie si le MSI est déjà installé (via DisplayName + DisplayVersion)
- Installe ou met à jour le package si nécessaire
- Journalise les opérations dans %ProgramData%\IMIO\Logs
- Doit s'exécuter en contexte SYSTEM (startup script GPO)
.NOTES
Auteur : Christophe Tourment / IMIO
Version : 1.0
Cible : Windows 11 Pro - PowerShell 5.1
#>
#Requires -Version 5.0
[CmdletBinding()]
param()
# ============================================================
# Configuration
# ============================================================
$ErrorActionPreference = 'Stop'
$MsiFileName = 'ZopeEdit-1.1.2.msi'
$ProductName = 'ZopeEdit'
$TargetVersion = '1.1.2'
$LogDir = Join-Path $env:ProgramData 'IMIO\Logs'
$LogFile = Join-Path $LogDir 'ZopeEdit-Deploy.log'
$MsiLogFile = Join-Path $LogDir "ZopeEdit-MsiInstall-$(Get-Date -Format 'yyyyMMdd-HHmmss').log"
$MarkerFile = Join-Path $env:ProgramData 'IMIO\ZopeEdit.installed'
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$MsiPath = Join-Path $ScriptDir $MsiFileName
# ============================================================
# Fonctions
# ============================================================
function Write-Log {
param(
[Parameter(Mandatory)][string]$Message,
[ValidateSet('INFO','WARN','ERROR','OK')][string]$Level = 'INFO'
)
$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
$line = "[$timestamp] [$Level] $Message"
try {
Add-Content -Path $LogFile -Value $line -Encoding UTF8 -ErrorAction Stop
} catch {}
Write-Verbose $line
}
function Get-InstalledProduct {
param([Parameter(Mandatory)][string]$Name)
$uninstallKeys = @(
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
Get-ItemProperty -Path $uninstallKeys -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -like "*$Name*" } |
Select-Object DisplayName, DisplayVersion, PSChildName, UninstallString
}
function Compare-Version {
param(
[Parameter(Mandatory)][string]$Installed,
[Parameter(Mandatory)][string]$Target
)
try {
$vInstalled = [version]$Installed
$vTarget = [version]$Target
return $vInstalled.CompareTo($vTarget)
} catch {
return [string]::Compare($Installed, $Target)
}
}
# ============================================================
# Initialisation
# ============================================================
try {
if (-not (Test-Path $LogDir)) {
New-Item -Path $LogDir -ItemType Directory -Force | Out-Null
}
} catch {}
Write-Log "===== Demarrage deploiement $ProductName v$TargetVersion =====" -Level INFO
Write-Log "Execute en tant que : $([Security.Principal.WindowsIdentity]::GetCurrent().Name)"
Write-Log "Machine : $env:COMPUTERNAME"
Write-Log "Chemin du script : $ScriptDir"
Write-Log "Chemin du MSI : $MsiPath"
# ============================================================
# Vérifications préalables
# ============================================================
if (-not (Test-Path -LiteralPath $MsiPath)) {
Write-Log "MSI introuvable : $MsiPath" -Level ERROR
exit 1
}
# ============================================================
# Vérification de l'état d'installation
# ============================================================
$installed = Get-InstalledProduct -Name $ProductName
if ($installed) {
foreach ($product in $installed) {
Write-Log "Produit detecte : $($product.DisplayName) v$($product.DisplayVersion)" -Level INFO
}
$current = $installed | Select-Object -First 1
if ($current.DisplayVersion) {
$cmp = Compare-Version -Installed $current.DisplayVersion -Target $TargetVersion
if ($cmp -ge 0) {
Write-Log "Version installee ($($current.DisplayVersion)) >= version cible ($TargetVersion). Rien a faire." -Level OK
exit 0
} else {
Write-Log "Version installee ($($current.DisplayVersion)) < version cible ($TargetVersion). Mise a jour requise." -Level INFO
}
}
} else {
Write-Log "Aucune installation existante detectee. Installation initiale." -Level INFO
}
# ============================================================
# Installation du MSI
# ============================================================
Write-Log "Lancement de msiexec..." -Level INFO
$msiArgs = @(
'/i'
"`"$MsiPath`""
'/qn'
'/norestart'
'REBOOT=ReallySuppress'
"/L*V `"$MsiLogFile`""
)
Write-Log "Commande : msiexec.exe $($msiArgs -join ' ')"
try {
$process = Start-Process -FilePath 'msiexec.exe' `
-ArgumentList $msiArgs `
-Wait -PassThru -NoNewWindow
$exitCode = $process.ExitCode
Write-Log "msiexec termine avec code : $exitCode"
switch ($exitCode) {
0 {
Write-Log "Installation reussie." -Level OK
try {
"$ProductName v$TargetVersion installe le $(Get-Date -Format 'o')" |
Set-Content -Path $MarkerFile -Encoding UTF8
} catch {}
exit 0
}
1605 {
Write-Log "Code 1605 : produit non trouve." -Level WARN
exit $exitCode
}
1618 {
Write-Log "Code 1618 : une autre installation MSI est en cours. Reessai au prochain demarrage." -Level WARN
exit $exitCode
}
1641 {
Write-Log "Code 1641 : installation reussie, reboot initie." -Level OK
exit 0
}
3010 {
Write-Log "Code 3010 : installation reussie, reboot requis." -Level OK
exit 0
}
default {
Write-Log "Echec installation. Consultez le log MSI : $MsiLogFile" -Level ERROR
exit $exitCode
}
}
}
catch {
Write-Log "Exception lors de l'execution de msiexec : $($_.Exception.Message)" -Level ERROR
exit 1
}
4. Configuration de la GPO#
4.1 Ouvrir la console GPMC#
Sur un contrôleur de domaine ou un poste avec RSAT :
Démarrer → Group Policy Management
4.2 Éditer la GPO cible#
Naviguer jusqu’à la GPO
{Unique ID}Clic droit → Edit
4.3 Activer l’ExecutionPolicy PowerShell#
Chemin dans l’éditeur GPO :
Computer Configuration
└── Policies
└── Administrative Templates
└── Windows Components
└── Windows PowerShell
└── Turn on Script Execution
Configuration :
Enabled
Execution Policy :
Allow local scripts and remote signed scripts
Note : sur les Startup Scripts, le script s’exécute depuis SYSVOL qui est considéré comme local. La policy
RemoteSignedpeut malgré tout bloquer selon le contexte ;Allow local scripts and remote signed scriptsest le compromis sûr.
4.4 Ajouter le script PowerShell de démarrage#
Chemin dans l’éditeur GPO :
Computer Configuration
└── Policies
└── Windows Settings
└── Scripts (Startup/Shutdown)
└── Startup
Étapes :
Double-cliquer sur Startup
Sélectionner l’onglet PowerShell Scripts (⚠️ pas l’onglet Scripts classique)
Cliquer sur Show Files… → cela ouvre le dossier SYSVOL
...\Machine\Scripts\Startup\Copier
Deploy-ZopeEdit.ps1etZopeEdit-1.1.2.msidans ce dossierFermer l’Explorateur
Cliquer sur Add…
Browse… → sélectionner
Deploy-ZopeEdit.ps1Laisser le champ Script Parameters vide
OK
4.5 Ordre d’exécution (optionnel)#
Si plusieurs scripts PowerShell coexistent, configurer l’option :
Run Windows PowerShell scripts first : Enabled
(Onglet PowerShell Scripts → bouton Properties en bas).
4.6 Forcer la mise à jour de la GPO#
Sur un poste client de test :
gpupdate /force
Puis redémarrer le poste — les Startup Scripts ne s’exécutent qu’au démarrage de la machine, pas lors d’un simple gpupdate.
5. Vérification du déploiement#
5.1 Vérifier l’application de la GPO sur le poste client#
gpresult /scope computer /h C:\Temp\gpo.html
Start-Process C:\Temp\gpo.html
Chercher la GPO {Unique ID} dans la section Computer Configuration → Applied GPOs.
5.2 Vérifier l’installation du logiciel#
Get-ItemProperty `
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*', `
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' |
Where-Object DisplayName -like '*Zope*' |
Select-Object DisplayName, DisplayVersion, Publisher, InstallDate
5.3 Consulter les logs#
Fichier |
Contenu |
|---|---|
|
Journal du script PowerShell |
|
Log verbeux msiexec |
|
Marker file (présent = installé) |
5.4 Vérifier le marker file#
Get-Content C:\ProgramData\IMIO\ZopeEdit.installed
Sortie attendue :
ZopeEdit v1.1.2 installe le 2026-05-28T08:15:32.0000000+02:00
6. Diagnostic et résolution de problèmes#
6.1 Codes de retour MSI#
Code |
Signification |
Action |
|---|---|---|
|
Installation réussie |
Aucune |
|
Erreur fatale d’installation |
Consulter le log MSI verbeux |
|
Produit non trouvé (pour désinstall) |
Normal lors de la première installation |
|
Autre installation MSI en cours |
Réessai automatique au prochain démarrage |
|
MSI introuvable ou inaccessible |
Vérifier le chemin SYSVOL |
|
Version déjà installée (autre instance) |
Vérifier le ProductCode du MSI |
|
Installation réussie, reboot initié |
Aucune |
|
Installation réussie, reboot requis |
Reboot manuel ou planifié |
6.2 Le script ne s’exécute pas#
Vérifier dans l’ordre :
GPO bien liée à l’OU contenant le poste :
gpresult /r /scope computer
Fichiers présents dans SYSVOL :
Test-Path '\\votre.commune.be\SYSVOL\votre.commune.be\Policies\{Unique ID}\Machine\Scripts\Startup\Deploy-ZopeEdit.ps1' Test-Path '\\votre.commune.be\SYSVOL\votre.commune.be\Policies\{Unique ID}\Machine\Scripts\Startup\ZopeEdit-1.1.2.msi'
Réplication SYSVOL complète entre tous les DC (DFSR opérationnel)
ExecutionPolicy correctement appliquée :
Get-ExecutionPolicy -List
Journal Événements Windows :
Event Viewer → Applications and Services Logs → Microsoft → Windows → GroupPolicy → Operational
6.3 Le MSI s’installe mais échoue#
Consulter le log MSI verbeux dans
C:\ProgramData\IMIO\Logs\Rechercher les chaînes
Return value 3(point d’échec) etMainEngineThread is returning(code final)Tester l’installation manuelle en local en tant qu’Administrateur :
msiexec.exe /i "C:\Temp\ZopeEdit-1.1.2.msi" /qn /L*V "C:\Temp\manual-install.log"
6.4 Cas particulier : DisplayName ne contient pas “ZopeEdit”#
Adapter la variable $ProductName dans le script en fonction du DisplayName réel détecté :
Get-ItemProperty `
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*', `
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' |
Where-Object DisplayName |
Select-Object DisplayName, DisplayVersion |
Sort-Object DisplayName
7. Désinstallation / rollback#
7.1 Désinstallation manuelle sur un poste#
# Récupérer le ProductCode
$product = Get-ItemProperty `
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*', `
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' |
Where-Object DisplayName -like '*ZopeEdit*' |
Select-Object -First 1
if ($product) {
$productCode = $product.PSChildName
Start-Process msiexec.exe -ArgumentList "/x $productCode /qn /norestart" -Wait
Remove-Item 'C:\ProgramData\IMIO\ZopeEdit.installed' -ErrorAction SilentlyContinue
}
7.2 Désactivation du déploiement#
Pour stopper le déploiement sur de nouveaux postes :
Éditer la GPO
{Unique ID}Onglet PowerShell Scripts → sélectionner
Deploy-ZopeEdit.ps1→ Removegpupdate /forcesur les DC
8. Annexes#
8.1 Arborescence finale dans SYSVOL#
\\votre.commune.be\SYSVOL\votre.commune.be\Policies\{Unique ID}\
└── Machine\
└── Scripts\
└── Startup\
├── Deploy-ZopeEdit.ps1
└── ZopeEdit-1.1.2.msi
8.2 Arborescence finale sur le poste client#
C:\ProgramData\IMIO\
├── ZopeEdit.installed
└── Logs\
├── ZopeEdit-Deploy.log
└── ZopeEdit-MsiInstall-20260528-081530.log
8.3 Références#
Documentation MSI Exit Codes : https://learn.microsoft.com/windows/win32/msi/error-codes
GPO PowerShell Startup Scripts : https://learn.microsoft.com/windows-server/administration/windows-commands/gpresult
Scalable Smart Package : documentation interne IMIO
Fin du document – DOC-IMIO-DEPLOY-ZopeEdit-v1.1.2