- Overzicht
- Variabelenconventies
- Step 1: Overzicht WinSxS-mapoptimalisatie
- Step 2: Overzicht Temp-mapopruiming
- Step 3: Overzicht logrotatie
- Step 4: Overzicht eventlog-onderhoud
- Step 5: Ontwerp van de scripts
- Step 6: Temp-opruimscript
- Step 7: Logrotatiescript
- Step 8: WinSxS-optimalisatiescript
- Step 9: Eventlog-onderhoudsscript
- Step 10: Voorbeelden voor registratie in Taakplanner
- Samenvatting
Overzicht
In dit artikel wordt uitgelegd hoe u periodieke schijfopruiming op Windows Server in vier taken opdeelt en per doel een eigen PowerShell-script gebruikt om de uitvoering te automatiseren:
- Optimalisatie van WinSxS (verkleinen van de component store)
- Opschonen van Temp-mappen (op basis van bewaartermijn)
- Logrotatie (meerdere paden, per pad eigen bewaartermijn)
- Back-up en opschonen van eventlogs
Variabelenconventies
| Variabelenaam | Voorbeeld | Opmerking |
|---|---|---|
<<ADMIN_USER>> |
Administrator |
Gebruiker waarmee de geplande taak wordt uitgevoerd |
<<LOG_PATH>> |
C:\Maintenance\Logs |
Gemeenschappelijke logdirectory |
<<BACKUP_PATH>> |
C:\Maintenance\Backups |
Directory voor eventlog-back-ups |
<<DAILY_TEMP_TASK_NAME>> |
DailyTempCleanup |
Taaknaam voor Temp-opruiming |
<<DAILY_LOG_TASK_NAME>> |
DailyLogRotation |
Taaknaam voor logrotatie |
<<MONTHLY_WINSXS_TASK_NAME>> |
MonthlyWinSxSCleanup |
Taaknaam voor WinSxS-optimalisatie |
<<MONTHLY_EVENTLOG_TASK_NAME>> |
MonthlyEventLogMaintenance |
Taaknaam voor eventlog-onderhoud |
Step 1: Overzicht WinSxS-mapoptimalisatie
C:\Windows\WinSxS is de component store waarin updates en componentversies worden opgeslagen. Deze map groeit naarmate het systeem langer in gebruik is. Optimalisatie gebeurt met DISM:
# Analyseren van de component store
Dism /Online /Cleanup-Image /AnalyzeComponentStore
# Opschonen van oude componenten
Dism /Online /Cleanup-Image /StartComponentCleanup
# Oude versies volledig verwijderen (rollback niet meer mogelijk)
Dism /Online /Cleanup-Image /StartComponentCleanup /ResetBase
Omdat /ResetBase de-installatie van oude updates onmogelijk maakt, is uitvoering bijvoorbeeld eens per maand tijdens een gepland onderhoudsvenster aan te raden.
Step 2: Overzicht Temp-mapopruiming
In $env:TEMP en C:\Windows\Temp worden tijdelijke bestanden van installers en applicaties verzameld. In de praktijk is het veiliger om “alle bestanden ouder dan X dagen te verwijderen” dan om alles zonder onderscheid te wissen.
Step 3: Overzicht logrotatie
Logdirectories groeien mee met het aantal applicaties en kunnen op termijn veel schijfruimte innemen. Omdat u per directory een eigen bewaartermijn wilt kunnen instellen, is een ontwerp op basis van een PSD1-configuratiebestand geschikt en flexibel.
Step 4: Overzicht eventlog-onderhoud
Eventlogs zijn essentieel voor storingsanalyse en audit. Ze mogen niet te vaak zonder back-up worden geleegd. Een veelgebruikt patroon is: eerst een back-up (.evtx) maken en daarna het log wissen, bijvoorbeeld ongeveer één keer per maand.
# Basisvoorbeeld voor back-up en leegmaken
wevtutil epl System C:\Logs\System_20250101.evtx
wevtutil cl System
Step 5: Ontwerp van de scripts
In dit artikel worden vier afzonderlijke scripts gebruikt:
-
cleanup_temp.ps1
Verwijdert oude bestanden uit Temp-mappen (bewaardagen als parameter). -
rotate_logs.ps1
Verwijdert verouderde.log-bestanden onder paden die in een PSD1-configuratiebestand zijn vastgelegd. -
optimize_winsxs.ps1
Voert/StartComponentCleanup /ResetBaseop WinSxS uit en logt de verschilgrootte. -
maintain_eventlogs.ps1
Maakt een back-up van opgegeven eventlogs en leegt deze daarna.
Met deze opzet kunnen de scripts per doel afzonderlijk vanuit Taakplanner worden uitgevoerd; dag- en maandtaken en beleidswijzigingen zijn eenvoudig aanpasbaar.
Voorbeeldentructuur:
C:\
└─ Maintenance\
├─ cleanup_temp.ps1 # Temp-mapopruiming (dagelijks)
├─ rotate_logs.ps1 # Logrotatie (dagelijks)
├─ optimize_winsxs.ps1 # WinSxS-optimalisatie (maandelijks)
├─ maintain_eventlogs.ps1 # Eventlog-back-up + clear (maandelijks)
│
├─ log_rotation.psd1 # Configuratiebestand logrotatie (meerdere paden + dagen)
│
├─ Logs\ # Uitvoeringslogs van de scripts
│ ├─ cleanup_temp_*.log
│ ├─ rotate_logs_*.log
│ ├─ optimize_winsxs_*.log
│ └─ eventlog_maint_*.log
│
└─ Backups\ # Back-up van eventlogs (EVTX)
├─ System_YYYYMMDD.evtx
├─ Application_YYYYMMDD.evtx
└─ Security_YYYYMMDD.evtx
Step 6: Temp-opruimscript
Dit script verwijdert alle bestanden en mappen onder de in $TempPaths opgegeven paden die ouder zijn dan DaysToKeep dagen en schrijft het resultaat naar een logbestand.
DaysToKeep en LogPath kunnen via parameters worden overschreven.
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: Logrotatiescript
Configuratiebestand voor logrotatie (PSD1)
Dit PSD1-bestand definieert meerdere doelmappen en bijbehorende bewaartermijnen. Voor een nieuwe logdirectory hoeft u alleen een extra entry toe te voegen.
log_rotation.psd1
@{
RotationTargets = @(
@{
Path = "C:\Logs\App1"
DaysToKeep = 7
},
@{
Path = "C:\Logs\App2"
DaysToKeep = 30
},
@{
Path = "<<LOG_PATH>>"
DaysToKeep = 7
}
)
}
Logrotatiescript
Dit script leest RotationTargets uit de PSD1 en verwijdert .log-bestanden onder elk pad die ouder zijn dan de geconfigureerde bewaartermijn. Alle acties worden gelogd.
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: WinSxS-optimalisatiescript
Dit script meet de grootte van de WinSxS-directory vóór en na de opruiming en voert vervolgens /StartComponentCleanup /ResetBase uit. Zo kunt u de gerealiseerde besparing kwantificeren.
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: Eventlog-onderhoudsscript
Dit script maakt een .evtx-back-up van de opgegeven logs (standaard System / Application / Security) in de back-updirectory en leegt daarna het oorspronkelijke log. Het logbestand bevat alle details over succes en fouten.
maintain_eventlogs.ps1
param(
[string]$LogPath = "<<LOG_PATH>>", # Opslaglocatie voor .log
[string]$BackupPath = "<<BACKUP_PATH>>", # Opslaglocatie voor EVTX-back-ups
[string[]]$EventLogs = @("System", "Application", "Security")
)
# Logdirectory aanmaken
if (-not (Test-Path $LogPath)) {
New-Item $LogPath -ItemType Directory -Force | Out-Null
}
# Back-updirectory aanmaken
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) {
# Per log een unieke EVTX-bestandsnaam
$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: Voorbeelden voor registratie in Taakplanner
Alle onderhoudsscripts worden hier met schtasks.exe geregistreerd.
Voor een volledige uitleg van opties zoals /SC, /D, /ST, /RU enzovoort, zie:
Beheer van Taakplanner met schtasks.exe
Dagelijkse Temp-opruiming
Dagelijks om 2:00 wordt cleanup_temp.ps1 uitgevoerd en worden Temp-bestanden ouder dan 7 dagen verwijderd.
De taak draait onder <<ADMIN_USER>> met hoogste machtigingen (/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
Dagelijkse logrotatie
Dagelijks om 2:30 wordt rotate_logs.ps1 uitgevoerd en worden .log-bestanden in meerdere directories op basis van de PSD1-configuratie geroteerd.
De bewaartermijnen worden volledig door log_rotation.psd1 bepaald.
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
Maandelijkse WinSxS-optimalisatie
Elke 1e dag van de maand om 3:00 wordt optimize_winsxs.ps1 uitgevoerd en wordt StartComponentCleanup /ResetBase inclusief maatmeting gedraaid.
Omdat rollback niet meer mogelijk is, moet dit binnen een gepland onderhoudsvenster gebeuren.
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
Maandelijks eventlog-onderhoud
Elke 1e dag van de maand om 3:30 wordt maintain_eventlogs.ps1 uitgevoerd en worden eventlogs zoals System / Application / Security naar de back-updirectory wegschreven en daarna geleegd.
Pas -EventLogs en -BackupPath aan volgens uw auditvereisten.
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
Samenvatting
Dit artikel beschrijft hoe u schijfonderhoud op Windows Server per doel in aparte scripts opsplitst en hoe u met een PSD1-configuratiebestand logrotatie flexibel beheert.
- Temp-opruiming: dagelijks, met instelbare bewaartermijn
- Logrotatie: meerdere paden en bewaartermijnen via PSD1
- WinSxS-optimalisatie: maandelijks, inclusief logging van besparing
- Eventlog-onderhoud: maandelijks, back-up plus clear
Zo ontstaat een robuuste, uitbreidbare automatisering van onderhoudstaken voor productieservers.
