Les Group Policy Objects sont au cœur de toute infrastructure Active Directory sérieuse. Elles définissent les paramètres de sécurité, les droits, les configurations des postes, les restrictions logicielles. En cas de sinistre, de mauvaise manipulation, ou simplement d’un besoin de revenir en arrière après un changement, ne pas avoir de sauvegarde de ses GPO c’est s’exposer à des heures de reconstruction laborieuse.
L’interface graphique de la console de gestion des stratégies de groupe propose bien une fonction de sauvegarde, mais elle est manuelle, oubliable, et surtout non versionnée. L’objectif de cet article est de l’automatiser proprement avec Ansible via WinRM, sur une infrastructure comportant deux domaines Active Directory distincts, avec archivage long terme sur un NAS et rapport par mail.
Architecture cible
L’infrastructure concernée repose sur :
- Deux domaines AD indépendants, chacun avec son contrôleur principal (PDC)
- Un serveur Ansible Linux qui pilote l’ensemble de l’infrastructure via des playbooks planifiés
- Un NAS TrueNAS Scale jouant le rôle d’archive long terme
- Un relay SMTP interne pour les notifications
La sauvegarde se déroule en plusieurs étapes :
- Connexion WinRM HTTPS (port 5986) sur chaque PDC
- Exécution de
Backup-GPOetGet-GPOReporten PowerShell - Rapatriement des fichiers vers le serveur Ansible
- Transfert vers le NAS via rsync over SSH
- Purge des sauvegardes de plus d’un an
- Envoi d’un rapport HTML par mail
Prérequis
Côté Windows
WinRM doit être actif sur les contrôleurs de domaine. Pour vérifier :
winrm enumerate winrm/config/listener
Si aucun listener n’est configuré :
winrm quickconfig -quiet
Le module PowerShell GroupPolicy doit être présent — il l’est nativement sur tout serveur promu en contrôleur de domaine.
Les comptes de service Ansible doivent disposer des droits Group Policy Creator Owners ou Domain Admins pour pouvoir exécuter Backup-GPO.
Côté Ansible
Le paquet pywinrm doit être installé sur le serveur Ansible :
pip install pywinrm --break-system-packages
Les mots de passe des comptes de service sont stockés dans un Ansible Vault dédié et ne transitent jamais en clair.
L’inventory
L’inventory définit les deux PDC avec leurs paramètres de connexion WinRM spécifiques à chaque domaine. Notez l’utilisation de ansible_winrm_scheme: https et du port 5986 — WinRM en HTTP clair sur 5985 n’est pas acceptable dans un environnement de production, même interne.
---
all:
children:
pdc_domaine1:
hosts:
PDC-DOM1:
ansible_host: 192.168.X.X
ansible_user: "domaine1\\ansible_svc"
ansible_password: "{{ vault_ansible_password_domaine1 }}"
ansible_connection: winrm
ansible_winrm_transport: ntlm
ansible_winrm_port: 5986
ansible_winrm_scheme: https
ansible_winrm_server_cert_validation: ignore
domain_name: domaine1.local
pdc_domaine2:
hosts:
PDC-DOM2:
ansible_host: 192.168.X.X
ansible_user: "domaine2\\ansible_svc"
ansible_password: "{{ vault_ansible_password_domaine2 }}"
ansible_connection: winrm
ansible_winrm_transport: ntlm
ansible_winrm_port: 5986
ansible_winrm_scheme: https
ansible_winrm_server_cert_validation: ignore
domain_name: domaine2.lan
La variable domain_name est une variable de host personnalisée — elle sera réutilisée dans le playbook pour nommer les dossiers de sauvegarde et personnaliser les messages de log.
Le playbook
Play 1 — Backup sur les PDC
Le premier play s’exécute sur les deux groupes d’hôtes en parallèle. Deux commandes PowerShell sont lancées :
Backup-GPO -Allcrée les sauvegardes individuelles dans des sous-dossiers identifiés par GUID — c’est le format natif, restaurable directement avecRestore-GPOGet-GPOReport -ReportType XMLgénère un rapport XML consolidé de toutes les GPO du domaine, avec leurs paramètres détaillés — c’est ce fichier qui sera utile pour une analyse future
- name: "{{ domain_name }} - Sauvegarder toutes les GPO"
ansible.windows.win_shell: |
Import-Module GroupPolicy
Backup-GPO -All -Path "C:\GPO_Backups\{{ domain_name }}"
Get-GPOReport -All -ReportType XML `
-Path "C:\GPO_Backups\{{ domain_name }}\all_gpo_report_{{ domain_name }}.xml"
register: gpo_result
Les fichiers sont ensuite rapatriés vers le serveur Ansible avec le module fetch, dans un répertoire temporaire daté.
Play 1 — Transfert vers le NAS
Le transfert utilise rsync via SSH avec sshpass pour l’authentification par mot de passe (une clé SSH dédiée serait plus élégante, mais les contraintes de l’environnement TrueNAS Scale ont orienté vers cette solution — sujet d’un prochain article). Les flags --no-perms --no-owner --no-group évitent les erreurs de permissions liées aux différences entre les systèmes de fichiers Linux et ZFS.
- name: "{{ domain_name }} - Copier vers le NAS via rsync"
delegate_to: localhost
shell: >
SSHPASS='{{ vault_password_nas }}'
sshpass -e rsync -avz --no-perms --no-owner --no-group --mkpath
-e "ssh -p PORT_SSH -o StrictHostKeyChecking=no"
/tmp/gpo_backups/{{ domain_name }}/{{ date_suffix }}/
user@nas-host:/mnt/ARCHIVE/DC_BACKUP/{{ domain_name }}/{{ date_suffix }}/
no_log: true
La purge des dossiers de plus de 365 jours s’effectue directement sur le NAS via SSH :
- name: "{{ domain_name }} - Purger les backups > 365 jours"
delegate_to: localhost
shell: >
SSHPASS='{{ vault_password_nas }}'
sshpass -e ssh -p PORT_SSH -o StrictHostKeyChecking=no user@nas-host
"find /mnt/ARCHIVE/DC_BACKUP/{{ domain_name }} -maxdepth 1 -type d -mtime +365 -exec rm -rf {} \;"
ignore_errors: true
no_log: true
Play 2 — Rapport HTML
Un second play s’exécute sur localhost après les sauvegardes. Il construit un rapport HTML en accédant aux variables enregistrées sur chaque hôte via hostvars, puis l’envoie via le relay SMTP interne.
Le rapport présente pour chaque domaine le statut de la sauvegarde PowerShell et le statut du transfert NAS, avec des indicateurs visuels ✅ / 🔴 pour une lecture rapide.
- name: Rapport backup GPO
hosts: localhost
gather_facts: yes
tasks:
- name: Envoyer le rapport par mail
ansible.builtin.mail:
host: smtp.domaine.local
port: 25
to: "admin@domaine.local"
from: "ansible@serveur.domaine.local"
subject: "Rapport backup GPO - {{ ansible_date_time.date }}"
body: "{{ recap_message }}"
secure: never
subtype: html
Structure des sauvegardes sur le NAS
/mnt/ARCHIVE/DC_BACKUP/
├── domaine1.local/
│ ├── 2026-03-31/
│ │ ├── all_gpo_report_domaine1.local.xml ← rapport consolidé
│ │ ├── {GUID-1}/ ← backup GPO individuelle
│ │ │ ├── Backup.xml
│ │ │ ├── bkupInfo.xml
│ │ │ └── DomainSysvol/
│ │ └── {GUID-2}/
│ └── 2026-04-07/
└── domaine2.lan/
└── 2026-04-07/
Chaque dossier GUID correspond à une GPO individuelle, dans le format natif de Windows — directement utilisable avec Restore-GPO ou la console GPMC sans aucune manipulation préalable.
Planification
Le playbook est planifié via cron tous les lundis matin, en cohérence avec les autres tâches de maintenance Ansible de l’infrastructure (mises à jour, backups réseau, backups NAS) :
# Backup GPO — tous les lundis à 8h45
45 8 * * 1 ansible-playbook /etc/ansible/playbooks/gpo-backup.yml \
-i /etc/ansible/inventory-windows.yml \
--vault-password-file /etc/ansible/vault/.vault_pass \
-e "@/etc/ansible/vault/network-secrets.yml" \
>> /var/log/ansible-gpo-backup.log 2>&1
Ce que cette sauvegarde permet — et ce qu’elle ne permet pas
Ce playbook produit des sauvegardes restaurables nativement avec Restore-GPO. En cas de suppression accidentelle d’une GPO ou de modification incorrecte, on peut revenir à l’état de la dernière sauvegarde en quelques minutes.
Le fichier all_gpo_report_*.xml a une valeur supplémentaire : il contient l’intégralité des paramètres de chaque GPO dans un format XML structuré. C’est ce fichier qui permet une analyse qualitative — détecter des redondances, des paramètres obsolètes, des GPO vides ou non liées. C’est un chantier que nous aborderons dans un prochain article : charger ce fichier dans un outil d’analyse pour auditer la cohérence d’un domaine AD.
Ce que ce playbook ne couvre pas en revanche : la sauvegarde du SYSVOL (scripts de démarrage, modèles ADMX personnalisés), qui nécessite une approche complémentaire. Pour une restauration complète en cas de sinistre majeur, c’est Veeam ou un équivalent qui prend le relais sur les DCs entiers.
Conclusion
Automatiser la sauvegarde des GPO avec Ansible et WinRM s’avère finalement assez direct, à condition de soigner trois points : l’authentification WinRM en HTTPS (et non en HTTP clair), le bon nommage des variables de vault pour les comptes de service, et la gestion des droits PowerShell côté Windows.
L’intérêt d’une telle approche par rapport à la sauvegarde manuelle GUI est triple : les sauvegardes sont régulières sans intervention humaine, elles sont versionnées par date sur un stockage dédié avec rétention longue durée, et elles s’intègrent dans le flux de reporting existant — un mail hebdomadaire consolidé qui donne une vue d’ensemble de la santé des sauvegardes de l’infrastructure.
Le prochain chantier logique est l’analyse du contenu de ces sauvegardes. Le rapport XML généré par Get-GPOReport est une mine d’informations — il attend d’être exploité.