- Panoramica
- Convenzioni delle variabili
- Step 1: Panoramica dell’ottimizzazione della cartella WinSxS
- Step 2: Panoramica della pulizia delle cartelle Temp
- Step 3: Panoramica della rotazione dei file di log
- Step 4: Panoramica della manutenzione dei log eventi
- Step 5: Linee guida di progettazione degli script
- Step 6: Script di pulizia Temp
- Step 7: Script di rotazione dei log
- Step 8: Script di ottimizzazione WinSxS
- Step 9: Script di manutenzione dei log eventi
- Step 10: Esempi di registrazione delle attività nell’Utilità di pianificazione
- Riepilogo
Panoramica
In questo articolo le attività periodiche di pulizia disco in Windows Server vengono suddivise in 4 categorie, illustrando come automatizzarle con script PowerShell indipendenti per ogni obiettivo:
- Ottimizzazione di WinSxS (riduzione dell’archivio componenti)
- Pulizia delle cartelle Temp (in base ai giorni di conservazione)
- Rotazione dei file di log (più percorsi, con giorni di conservazione separati)
- Backup + svuotamento dei log eventi
Convenzioni delle variabili
| Variabile | Esempio | Note |
|---|---|---|
<<ADMIN_USER>> |
Administrator |
Account che esegue le attività pianificate |
<<LOG_PATH>> |
C:\Maintenance\Logs |
Directory comune per i log degli script |
<<BACKUP_PATH>> |
C:\Maintenance\Backups |
Directory per il backup dei log eventi |
<<DAILY_TEMP_TASK_NAME>> |
DailyTempCleanup |
Nome attività di pulizia Temp |
<<DAILY_LOG_TASK_NAME>> |
DailyLogRotation |
Nome attività di rotazione log |
<<MONTHLY_WINSXS_TASK_NAME>> |
MonthlyWinSxSCleanup |
Nome attività di ottimizzazione WinSxS |
<<MONTHLY_EVENTLOG_TASK_NAME>> |
MonthlyEventLogMaintenance |
Nome attività di manutenzione log eventi |
Step 1: Panoramica dell’ottimizzazione della cartella WinSxS
C:\Windows\WinSxS è l’archivio componenti (Component Store), che conserva la cronologia degli aggiornamenti e dei componenti di funzionalità. Con il tempo può crescere in modo significativo; è possibile ottimizzarlo con i seguenti comandi DISM:
# Analisi dell’archivio componenti
Dism /Online /Cleanup-Image /AnalyzeComponentStore
# Pulizia dei componenti obsoleti
Dism /Online /Cleanup-Image /StartComponentCleanup
# Rimozione completa delle versioni precedenti (nessun rollback possibile)
Dism /Online /Cleanup-Image /StartComponentCleanup /ResetBase
Poiché /ResetBase rende impossibile disinstallare gli aggiornamenti precedenti, è consigliabile eseguirlo solo in modo pianificato, ad esempio una volta al mese durante una finestra di manutenzione.
Step 2: Panoramica della pulizia delle cartelle Temp
Nelle directory $env:TEMP e C:\Windows\Temp si accumulano file temporanei creati da installer e applicazioni. Invece di cancellare tutto alla cieca, una strategia più sicura è:
“Eliminare i file più vecchi di N giorni”.
Step 3: Panoramica della rotazione dei file di log
I percorsi di log aumentano con il numero di applicazioni e, se conservati a lungo, possono saturare il disco. Poiché è utile assegnare giorni di conservazione diversi per ciascuna directory, è opportuno usare un file di configurazione PSD1 per gestire la rotazione in modo flessibile.
Step 4: Panoramica della manutenzione dei log eventi
I log eventi sono fondamentali per diagnosi guasti e audit, quindi non dovrebbero essere svuotati di frequente senza backup. Una prassi comune è eseguire un backup in formato .evtx e successivamente svuotare il log, ad esempio circa una volta al mese:
# Esempio base di backup e svuotamento
wevtutil epl System C:\Logs\System_20250101.evtx
wevtutil cl System
Step 5: Linee guida di progettazione degli script
In questo articolo prepariamo quattro script distinti, uno per ciascun obiettivo:
-
cleanup_temp.ps1
Elimina i file obsoleti nelle cartelle Temp (giorni di conservazione configurabili via parametro). -
rotate_logs.ps1
Usa un file PSD1 per definire le directory di log e i relativi giorni di conservazione, ed elimina i.logscaduti. -
optimize_winsxs.ps1
Esegue/StartComponentCleanup /ResetBasesu WinSxS e registra la quantità di spazio liberato. -
maintain_eventlogs.ps1
Esegue il backup dei log eventi specificati e li svuota.
Con questa struttura, dall’Utilità di pianificazione è possibile eseguire selettivamente ogni script (giornaliero/mensile) e adattare facilmente la policy in base alle esigenze.
Esempio di struttura di directory prevista:
C:\
└─ Maintenance\
├─ cleanup_temp.ps1 # Pulizia cartelle Temp (giornaliera)
├─ rotate_logs.ps1 # Rotazione dei log (giornaliera)
├─ optimize_winsxs.ps1 # Ottimizzazione WinSxS (mensile)
├─ maintain_eventlogs.ps1 # Backup + svuotamento log eventi (mensile)
│
├─ log_rotation.psd1 # Configurazione rotazione log (più percorsi + giorni)
│
├─ Logs\ # Log di esecuzione degli script
│ ├─ cleanup_temp_*.log
│ ├─ rotate_logs_*.log
│ ├─ optimize_winsxs_*.log
│ └─ eventlog_maint_*.log
│
└─ Backups\ # Backup EVTX dei log eventi
├─ System_YYYYMMDD.evtx
├─ Application_YYYYMMDD.evtx
└─ Security_YYYYMMDD.evtx
Step 6: Script di pulizia Temp
Questo script elimina in modo ricorsivo file e cartelle più vecchi di DaysToKeep giorni sotto i percorsi specificati in $TempPaths, registrando il risultato in un file di log.
È possibile sovrascrivere DaysToKeep e LogPath tramite parametri.
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 di rotazione dei log
File di configurazione della rotazione (PSD1)
Questo file PSD1 definisce più coppie directory di log + giorni di conservazione. Per aggiungere una nuova directory di log, è sufficiente aggiungere una voce all’array.
log_rotation.psd1
@{
RotationTargets = @(
@{
Path = "C:\Logs\App1"
DaysToKeep = 7
},
@{
Path = "C:\Logs\App2"
DaysToKeep = 30
},
@{
Path = "<<LOG_PATH>>"
DaysToKeep = 7
}
)
}
Script di rotazione dei log
Questo script legge RotationTargets dal file PSD1 e, per ogni percorso, elimina i file .log più vecchi della soglia configurata, registrando tutte le operazioni nei log.
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 di ottimizzazione WinSxS
Questo script esegue /StartComponentCleanup /ResetBase su WinSxS e misura la dimensione della directory prima e dopo, registrandola nei log. In questo modo è possibile quantificare lo spazio effettivamente liberato.
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 di manutenzione dei log eventi
Questo script, per i log specificati (per impostazione predefinita System / Application / Security), esegue un backup in formato .evtx nella directory di backup e poi svuota i log originali. Tutti i risultati vengono riportati in un file di log.
maintain_eventlogs.ps1
param(
[string]$LogPath = "<<LOG_PATH>>", # Destinazione per i log (.log)
[string]$BackupPath = "<<BACKUP_PATH>>", # Destinazione per i backup EVTX
[string[]]$EventLogs = @("System", "Application", "Security")
)
# Creazione della directory per i log
if (-not (Test-Path $LogPath)) {
New-Item $LogPath -ItemType Directory -Force | Out-Null
}
# Creazione della directory per i backup
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) {
# Genera un nome EVTX univoco per ogni log
$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: Esempi di registrazione delle attività nell’Utilità di pianificazione
Di seguito vengono mostrati esempi di registrazione di tutte le attività di manutenzione tramite schtasks.exe.
Per una spiegazione dettagliata delle opzioni /SC, /D, /ST, /RU e di altri pattern, vedere:
Gestione dell’Utilità di pianificazione con schtasks.exe
Pulizia Temp (attività giornaliera)
Esegue cleanup_temp.ps1 ogni giorno alle 2:00, eliminando i file Temp più vecchi di 7 giorni.
L’attività viene eseguita con l’account <<ADMIN_USER>> con massimi privilegi (/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
Rotazione log (attività giornaliera)
Esegue rotate_logs.ps1 ogni giorno alle 2:30, ruotando i file .log in più directory in base alla configurazione PSD1.
I giorni di conservazione vengono impostati solo in 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
Ottimizzazione WinSxS (attività mensile)
Esegue optimize_winsxs.ps1 il giorno 1 di ogni mese alle 3:00, lanciando StartComponentCleanup /ResetBase e misurando la dimensione prima/dopo.
Poiché comprende operazioni non reversibili, va pianificata in una finestra di manutenzione.
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
Manutenzione log eventi (attività mensile)
Esegue maintain_eventlogs.ps1 il giorno 1 di ogni mese alle 3:30, spostando i log eventi (System / Application / Security, ecc.) nella directory di backup e svuotandoli.
Adeguare -EventLogs e -BackupPath secondo i requisiti di 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
Riepilogo
In questo articolo la manutenzione del disco in Windows Server è stata scomposta in script specializzati per finalità, e tramite un file di configurazione PSD1 è stato reso possibile gestire in modo flessibile percorsi di log e giorni di conservazione:
- Pulizia Temp: esecuzione giornaliera, giorni di conservazione configurabili
- Rotazione log: gestione di più percorsi e policy tramite PSD1
- Ottimizzazione WinSxS: esecuzione mensile, con misura dello spazio liberato
- Manutenzione log eventi: esecuzione mensile, con backup EVTX prima dello svuotamento
Questa struttura costituisce una base riutilizzabile per automatizzare la manutenzione del disco nei server Windows in ambienti di produzione, estendibile con ulteriori script e attività programmate.
