- Vue d’ensemble
- Convention de variables
- Step 1: Vue d’ensemble de l’optimisation du dossier WinSxS
- Step 2: Vue d’ensemble du nettoyage des dossiers temporaires
- Step 3: Vue d’ensemble de la rotation des fichiers journaux
- Step 4: Vue d’ensemble de la maintenance des journaux d’événements
- Step 5: Stratégie de conception des scripts
- Step 6: Script de nettoyage des dossiers temporaires
- Step 7: Script de rotation des journaux
- Step 8: Script d’optimisation de WinSxS
- Step 9: Script de maintenance des journaux d’événements
- Step 10: Exemples d’enregistrement dans le Planificateur de tâches
- Résumé
Vue d’ensemble
Cet article présente une manière de structurer les tâches récurrentes de nettoyage de disque sur Windows Server en quatre catégories, chacune automatisée par un script PowerShell indépendant :
- Optimisation de WinSxS (réduction du component store)
- Nettoyage des dossiers temporaires (par durée de rétention)
- Rotation des fichiers journaux (plusieurs chemins avec durée de rétention propre)
- Sauvegarde et nettoyage des journaux d’événements
Convention de variables
| Nom de variable | Exemple | Remarque |
|---|---|---|
<<ADMIN_USER>> |
Administrator |
Compte utilisé pour exécuter les tâches planifiées |
<<LOG_PATH>> |
C:\Maintenance\Logs |
Répertoire commun pour les journaux d’exécution des scripts |
<<BACKUP_PATH>> |
C:\Maintenance\Backups |
Répertoire de sauvegarde des journaux d’événements |
<<DAILY_TEMP_TASK_NAME>> |
DailyTempCleanup |
Nom de la tâche de nettoyage Temp |
<<DAILY_LOG_TASK_NAME>> |
DailyLogRotation |
Nom de la tâche de rotation des journaux |
<<MONTHLY_WINSXS_TASK_NAME>> |
MonthlyWinSxSCleanup |
Nom de la tâche d’optimisation WinSxS |
<<MONTHLY_EVENTLOG_TASK_NAME>> |
MonthlyEventLogMaintenance |
Nom de la tâche de maintenance des journaux d’événements |
Step 1: Vue d’ensemble de l’optimisation du dossier WinSxS
C:\Windows\WinSxS est le component store, qui conserve l’historique des mises à jour et des composants de fonctionnalités. À long terme, ce dossier a tendance à grossir et peut être optimisé avec les commandes DISM suivantes :
# Analyse du component store
Dism /Online /Cleanup-Image /AnalyzeComponentStore
# Nettoyage des anciens composants
Dism /Online /Cleanup-Image /StartComponentCleanup
# Suppression complète des anciennes versions (retour arrière impossible)
Dism /Online /Cleanup-Image /StartComponentCleanup /ResetBase
Comme l’option /ResetBase rend impossible la désinstallation des anciennes mises à jour, il est plus sûr de l’exécuter une fois par mois environ, dans une fenêtre de maintenance planifiée.
Step 2: Vue d’ensemble du nettoyage des dossiers temporaires
Les emplacements $env:TEMP et C:\Windows\Temp contiennent des fichiers temporaires créés par des installateurs et des applications. Plutôt que de tout supprimer en bloc, il est plus réaliste d’appliquer une politique du type :
« Supprimer les fichiers plus anciens que X jours ».
Step 3: Vue d’ensemble de la rotation des fichiers journaux
Les répertoires de journaux se multiplient avec le nombre d’applications et, sur le long terme, remplissent le disque. Comme il est souhaitable de définir une durée de rétention spécifique par répertoire, on utilise un fichier de configuration PSD1 pour gérer ces paramètres de manière flexible.
Step 4: Vue d’ensemble de la maintenance des journaux d’événements
Les journaux d’événements sont essentiels pour l’investigation des incidents et l’audit, il ne faut donc jamais les effacer régulièrement sans sauvegarde préalable. Un modèle courant (par exemple une fois par mois) consiste à exporter d’abord en .evtx, puis à effacer le journal.
# Modèle de base : sauvegarde et nettoyage
wevtutil epl System C:\Logs\System_20250101.evtx
wevtutil cl System
Step 5: Stratégie de conception des scripts
Nous allons utiliser quatre scripts, chacun dédié à un objectif précis :
-
cleanup_temp.ps1
Supprime les anciens fichiers dans les dossiers temporaires (durée de rétention en paramètre). -
rotate_logs.ps1
Supprime les fichiers.logdans les répertoires spécifiés par le fichier de configuration PSD1. -
optimize_winsxs.ps1
Exécute/StartComponentCleanup /ResetBasepour WinSxS et enregistre le volume d’espace libéré. -
maintain_eventlogs.ps1
Sauvegarde en.evtxles journaux d’événements spécifiés, puis les efface.
Cette séparation permet d’exécuter chaque script individuellement depuis le Planificateur de tâches, et de combiner des plannings quotidiens / mensuels ou de modifier la politique sans impact sur les autres tâches.
Structure de répertoires de référence :
C:\
└─ Maintenance\
├─ cleanup_temp.ps1 # Nettoyage des dossiers temporaires (quotidien)
├─ rotate_logs.ps1 # Rotation des journaux (quotidien)
├─ optimize_winsxs.ps1 # Optimisation WinSxS (mensuel)
├─ maintain_eventlogs.ps1 # Sauvegarde + nettoyage des journaux d’événements (mensuel)
│
├─ log_rotation.psd1 # Fichier PSD1 de configuration (plusieurs chemins + rétention)
│
├─ Logs\ # Journaux d’exécution des scripts
│ ├─ cleanup_temp_*.log
│ ├─ rotate_logs_*.log
│ ├─ optimize_winsxs_*.log
│ └─ eventlog_maint_*.log
│
└─ Backups\ # Sauvegardes des journaux d’événements (EVTX)
├─ System_YYYYMMDD.evtx
├─ Application_YYYYMMDD.evtx
└─ Security_YYYYMMDD.evtx
Step 6: Script de nettoyage des dossiers temporaires
Ce script parcourt les dossiers répertoriés dans $TempPaths et supprime récursivement les fichiers et sous-dossiers plus anciens que DaysToKeep jours, tout en journalisant les opérations.
Les paramètres DaysToKeep et LogPath peuvent être surchargés à l’exécution.
cleanup_temp.ps1
param(
[string[]]$TempPaths = @("$env:TEMP", "C:\Windows\Temp"),
[int]$DaysToKeep = 7,
[string]$LogPath = "<<LOG_PATH>>"
)
if (-not (Test-Path $LogPath)) {
New-Item $LogPath -ItemType Directory -Force | Out-Null
}
$timestamp = Get-Date -Format 'yyyyMMdd_HHmmss'
$logFile = Join-Path $LogPath "cleanup_temp_$timestamp.log"
function Write-Log($Message) {
"[{0}] {1}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $Message |
Tee-Object -FilePath $logFile -Append
}
Write-Log "===== Temp cleanup started ====="
Write-Log "DaysToKeep = $DaysToKeep"
$limitDate = (Get-Date).AddDays(-$DaysToKeep)
foreach ($path in $TempPaths) {
if (-not (Test-Path $path)) {
Write-Log "Skip: Not found -> $path"
continue
}
Write-Log "Processing: $path"
Get-ChildItem -Path $path -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -lt $limitDate } |
ForEach-Object {
try {
Remove-Item -LiteralPath $_.FullName -Force -Recurse -ErrorAction Stop
Write-Log "Deleted: $($_.FullName)"
}
catch {
Write-Log "Failed: $($_.FullName) - $($_.Exception.Message)"
}
}
}
Write-Log "===== Temp cleanup finished ====="
Step 7: Script de rotation des journaux
Fichier de configuration de rotation (PSD1)
Ce fichier PSD1 définit plusieurs couples (répertoire, durée de rétention). Pour ajouter un nouveau répertoire de journaux, il suffit d’ajouter une entrée dans ce fichier.
log_rotation.psd1
@{
RotationTargets = @(
@{
Path = "C:\Logs\App1"
DaysToKeep = 7
},
@{
Path = "C:\Logs\App2"
DaysToKeep = 30
},
@{
Path = "<<LOG_PATH>>"
DaysToKeep = 7
}
)
}
Script de rotation des journaux
Ce script lit RotationTargets depuis le fichier PSD1 et supprime les fichiers .log plus anciens que la durée de rétention calculée dans chaque répertoire. Toutes les opérations sont consignées dans un fichier journal.
rotate_logs.ps1
param(
[string]$ConfigPath = "C:\Maintenance\log_rotation.psd1",
[string]$LogPath = "<<LOG_PATH>>"
)
if (-not (Test-Path $LogPath)) {
New-Item $LogPath -ItemType Directory -Force | Out-Null
}
$timestamp = Get-Date -Format 'yyyyMMdd_HHmmss'
$logFile = Join-Path $LogPath "rotate_logs_$timestamp.log"
function Write-Log($Message) {
"[{0}] {1}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $Message |
Tee-Object -FilePath $logFile -Append
}
Write-Log "===== Log rotation started ====="
Write-Log "ConfigPath = $ConfigPath"
if (-not (Test-Path $ConfigPath)) {
Write-Log "Config file not found. Exit."
exit 1
}
try {
$config = Import-PowerShellDataFile -Path $ConfigPath
}
catch {
Write-Log "Config load failed: $($_.Exception.Message)"
exit 1
}
foreach ($target in $config.RotationTargets) {
$targetPath = $target.Path
$daysToKeep = [int]$target.DaysToKeep
if (-not (Test-Path $targetPath)) {
Write-Log "Skip (not found): $targetPath"
continue
}
$limitDate = (Get-Date).AddDays(-$daysToKeep)
Write-Log "Path=$targetPath DaysToKeep=$daysToKeep Limit=$limitDate"
Get-ChildItem -Path $targetPath -Recurse -Include *.log -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -lt $limitDate } |
ForEach-Object {
try {
Remove-Item -LiteralPath $_.FullName -Force -ErrorAction Stop
Write-Log "Deleted: $($_.FullName)"
}
catch {
Write-Log "Failed: $($_.FullName) - $($_.Exception.Message)"
}
}
}
Write-Log "===== Log rotation finished ====="
Step 8: Script d’optimisation de WinSxS
Ce script mesure la taille du répertoire WinSxS avant et après l’opération et exécute /StartComponentCleanup /ResetBase. Il permet de quantifier l’espace réellement libéré.
optimize_winsxs.ps1
param(
[string]$LogPath = "<<LOG_PATH>>"
)
if (-not (Test-Path $LogPath)) {
New-Item $LogPath -ItemType Directory -Force | Out-Null
}
$timestamp = Get-Date -Format 'yyyyMMdd_HHmmss'
$logFile = Join-Path $LogPath "optimize_winsxs_$timestamp.log"
function Write-Log($Message) {
"[{0}] {1}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $Message |
Tee-Object -FilePath $logFile -Append
}
Write-Log "===== WinSxS optimization started ====="
$winsxsPath = "C:\Windows\WinSxS"
Write-Log "Measuring WinSxS size before..."
$sizeBefore = (Get-ChildItem $winsxsPath -Recurse -Force -ErrorAction SilentlyContinue |
Measure-Object Length -Sum).Sum
$sizeBeforeGB = [math]::Round($sizeBefore / 1GB, 2)
Write-Log "Before: $sizeBeforeGB GB"
Dism /Online /Cleanup-Image /AnalyzeComponentStore |
Out-File (Join-Path $LogPath "dism_before_$timestamp.txt")
Write-Log "Running StartComponentCleanup /ResetBase..."
Dism /Online /Cleanup-Image /StartComponentCleanup /ResetBase |
Out-File (Join-Path $LogPath "dism_exec_$timestamp.txt")
Write-Log "Measuring WinSxS size after..."
$sizeAfter = (Get-ChildItem $winsxsPath -Recurse -Force -ErrorAction SilentlyContinue |
Measure-Object Length -Sum).Sum
$sizeAfterGB = [math]::Round($sizeAfter / 1GB, 2)
Write-Log "After: $sizeAfterGB GB"
Write-Log ("Reduced: {0} GB" -f ([math]::Round(($sizeBefore - $sizeAfter)/1GB,2)))
Dism /Online /Cleanup-Image /AnalyzeComponentStore |
Out-File (Join-Path $LogPath "dism_after_$timestamp.txt")
Write-Log "===== WinSxS optimization finished ====="
Step 9: Script de maintenance des journaux d’événements
Ce script exporte les journaux spécifiés (par défaut : System / Application / Security) dans des fichiers .evtx dans le répertoire de sauvegarde, puis efface les journaux d’origine. Les succès et erreurs sont détaillés dans un fichier journal.
maintain_eventlogs.ps1
param(
[string]$LogPath = "<<LOG_PATH>>", # Dossier de journaux (.log)
[string]$BackupPath = "<<BACKUP_PATH>>", # Dossier de sauvegarde EVTX
[string[]]$EventLogs = @("System", "Application", "Security")
)
# Création du dossier pour les journaux si nécessaire
if (-not (Test-Path $LogPath)) {
New-Item $LogPath -ItemType Directory -Force | Out-Null
}
# Création du dossier de sauvegarde si nécessaire
if (-not (Test-Path $BackupPath)) {
New-Item $BackupPath -ItemType Directory -Force | Out-Null
}
$timestamp = Get-Date -Format 'yyyyMMdd_HHmmss'
$logFile = Join-Path $LogPath "eventlog_maint_$timestamp.log"
function Write-Log($Message) {
"[{0}] {1}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $Message |
Tee-Object -FilePath $logFile -Append
}
Write-Log "===== Event log maintenance started ====="
Write-Log "BackupPath = $BackupPath"
foreach ($name in $EventLogs) {
# Nom EVTX unique pour chaque journal
$destEvtx = Join-Path $BackupPath ("{0}_{1}.evtx" -f $name, $timestamp)
try {
Write-Log "Export: $name -> $destEvtx"
wevtutil epl $name $destEvtx
Write-Log "Clear: $name"
wevtutil cl $name
}
catch {
Write-Log "Failed: $name - $($_.Exception.Message)"
}
}
Write-Log "===== Event log maintenance finished ====="
Step 10: Exemples d’enregistrement dans le Planificateur de tâches
Les exemples suivants montrent comment enregistrer chaque script de maintenance dans le Planificateur de tâches à l’aide de schtasks.exe.
Pour une explication détaillée des options /SC, /D, /ST, /RU, etc., voir l’article suivant :
Gestion du Planificateur de tâches avec schtasks.exe
Exemple de tâche quotidienne de nettoyage Temp
Cette tâche exécute cleanup_temp.ps1 chaque jour à 2h00 pour supprimer les fichiers Temp plus anciens que 7 jours.
Elle s’exécute sous le compte <<ADMIN_USER>> avec les privilèges les plus élevés (/RL HIGHEST).
schtasks /Create `
/TN "<<DAILY_TEMP_TASK_NAME>>" `
/TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Maintenance\cleanup_temp.ps1 -DaysToKeep 7 -LogPath <<LOG_PATH>>" `
/SC DAILY `
/ST 02:00 `
/RU "<<ADMIN_USER>>" `
/RL HIGHEST `
/F
Exemple de tâche quotidienne de rotation des journaux
Cette tâche exécute rotate_logs.ps1 chaque jour à 2h30 pour effectuer la rotation des fichiers .log dans plusieurs répertoires, selon la configuration PSD1.
Les durées de rétention sont définies exclusivement dans log_rotation.psd1.
schtasks /Create `
/TN "<<DAILY_LOG_TASK_NAME>>" `
/TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Maintenance\rotate_logs.ps1 -ConfigPath C:\Maintenance\log_rotation.psd1 -LogPath <<LOG_PATH>>" `
/SC DAILY `
/ST 02:30 `
/RU "<<ADMIN_USER>>" `
/RL HIGHEST `
/F
Exemple de tâche mensuelle d’optimisation WinSxS
Cette tâche exécute optimize_winsxs.ps1 le 1er de chaque mois à 3h00 et lance StartComponentCleanup /ResetBase avec mesure de la taille avant/après.
Comme l’opération est irréversible, planifiez-la dans une fenêtre de maintenance contrôlée.
schtasks /Create `
/TN "<<MONTHLY_WINSXS_TASK_NAME>>" `
/TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Maintenance\optimize_winsxs.ps1 -LogPath <<LOG_PATH>>" `
/SC MONTHLY `
/D 1 `
/ST 03:00 `
/RU "<<ADMIN_USER>>" `
/RL HIGHEST `
/F
Exemple de tâche mensuelle de maintenance des journaux d’événements
Cette tâche exécute maintain_eventlogs.ps1 le 1er de chaque mois à 3h30 pour sauvegarder les journaux System / Application / Security dans le répertoire de sauvegarde, puis les effacer.
Adaptez -EventLogs et -BackupPath selon vos exigences d’audit.
schtasks /Create `
/TN "<<MONTHLY_EVENTLOG_TASK_NAME>>" `
/TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Maintenance\maintain_eventlogs.ps1 -LogPath <<LOG_PATH>>" `
/SC MONTHLY `
/D 1 `
/ST 03:30 `
/RU "<<ADMIN_USER>>" `
/RL HIGHEST `
/F
Résumé
Cette approche décompose la maintenance de disque sous Windows Server en scripts spécialisés par objectif et s’appuie sur un fichier de configuration PSD1 pour gérer de manière flexible les répertoires de journaux et leurs durées de rétention.
- Suppression Temp : exécution quotidienne, durée de rétention paramétrable
- Rotation des journaux : plusieurs chemins et durées de rétention définis dans PSD1
- Optimisation WinSxS : exécution mensuelle, journalisation du volume libéré
- Maintenance des journaux d’événements : exécution mensuelle avec sauvegarde au format EVTX, puis nettoyage
Ce modèle fournit une base robuste et extensible pour automatiser la maintenance dans des environnements de production Windows Server.
