- Visão geral
- Convenções de variáveis
- Step 1: Visão geral da otimização da pasta WinSxS
- Step 2: Visão geral da limpeza de pastas temporárias
- Step 3: Visão geral da rotação de arquivos de log
- Step 4: Visão geral da manutenção de logs de eventos
- Step 5: Diretrizes de desenho dos scripts
- Step 6: Script de limpeza de Temp
- Step 7: Script de rotação de logs
- Step 8: Script de otimização do WinSxS
- Step 9: Script de manutenção de logs de eventos
- Step 10: Exemplos de registro no Agendador de Tarefas
- Resumo
Visão geral
Este artigo mostra como dividir as tarefas periódicas de limpeza de disco em servidores Windows em quatro áreas e automatizá-las com scripts PowerShell independentes para cada objetivo:
- Otimização do WinSxS (redução do component store)
- Limpeza de pastas temporárias (por dias de retenção)
- Rotação de arquivos de log (múltiplos caminhos, cada um com sua retenção)
- Backup e limpeza de logs de eventos
Convenções de variáveis
| Nome da variável | Exemplo | Observação |
|---|---|---|
<<ADMIN_USER>> |
Administrator |
Usuário que executa as tarefas agendadas |
<<LOG_PATH>> |
C:\Maintenance\Logs |
Diretório comum para logs de execução |
<<BACKUP_PATH>> |
C:\Maintenance\Backups |
Diretório para backup de logs de eventos |
<<DAILY_TEMP_TASK_NAME>> |
DailyTempCleanup |
Nome da tarefa de limpeza de Temp |
<<DAILY_LOG_TASK_NAME>> |
DailyLogRotation |
Nome da tarefa de rotação de logs |
<<MONTHLY_WINSXS_TASK_NAME>> |
MonthlyWinSxSCleanup |
Nome da tarefa de otimização do WinSxS |
<<MONTHLY_EVENTLOG_TASK_NAME>> |
MonthlyEventLogMaintenance |
Nome da tarefa de manutenção dos logs de eventos |
Step 1: Visão geral da otimização da pasta WinSxS
C:\Windows\WinSxS é o component store que mantém o histórico de atualizações e componentes. Ele tende a crescer ao longo do tempo e pode ser otimizado com os comandos DISM a seguir:
# Analisar o component store
Dism /Online /Cleanup-Image /AnalyzeComponentStore
# Limpar componentes antigos
Dism /Online /Cleanup-Image /StartComponentCleanup
# Remover completamente versões antigas (sem possibilidade de rollback)
Dism /Online /Cleanup-Image /StartComponentCleanup /ResetBase
Como /ResetBase torna impossível desinstalar atualizações antigas, é mais seguro executá-lo apenas em momentos planejados, por exemplo, uma vez por mês durante uma janela de manutenção.
Step 2: Visão geral da limpeza de pastas temporárias
Em $env:TEMP e C:\Windows\Temp acumulam-se arquivos temporários criados por instaladores e aplicações. Em vez de apagar tudo indiscriminadamente, é mais seguro aplicar a política:
“apagar arquivos mais antigos do que X dias”.
Step 3: Visão geral da rotação de arquivos de log
Diretórios de log crescem com o tempo e podem consumir muito espaço em disco. Como é desejável definir dias de retenção específicos por diretório, usamos um arquivo de configuração PSD1 para gerenciar os alvos de forma flexível.
Step 4: Visão geral da manutenção de logs de eventos
Logs de eventos são críticos para análise de incidentes e auditoria, portanto não devem ser limpos com frequência sem backup. Uma prática comum é executar, cerca de uma vez por mês, o seguinte padrão: exportar para .evtx e depois limpar.
# Exemplo básico de backup e limpeza
wevtutil epl System C:\Logs\System_20250101.evtx
wevtutil cl System
Step 5: Diretrizes de desenho dos scripts
Neste artigo, usamos quatro scripts, um para cada objetivo:
-
cleanup_temp.ps1
Remove arquivos antigos em pastas temporárias (dias de retenção configuráveis por parâmetro). -
rotate_logs.ps1
Remove arquivos.logsob diretórios definidos em um arquivo de configuração PSD1. -
optimize_winsxs.ps1
Executa/StartComponentCleanup /ResetBaseno WinSxS e registra a quantidade de espaço liberado. -
maintain_eventlogs.ps1
Exporta logs de eventos especificados para.evtxe, em seguida, limpa esses logs.
Com essa estrutura, cada script pode ser executado separadamente pelo Agendador de Tarefas, permitindo combinações de agendamentos diários/mensais e ajustes de política com facilidade.
Estrutura de diretórios sugerida:
C:\
└─ Maintenance\
├─ cleanup_temp.ps1 # Limpeza de pastas Temp (diária)
├─ rotate_logs.ps1 # Rotação de logs (diária)
├─ optimize_winsxs.ps1 # Otimização do WinSxS (mensal)
├─ maintain_eventlogs.ps1 # Backup + limpeza de logs de eventos (mensal)
│
├─ log_rotation.psd1 # Configuração de rotação (múltiplos caminhos + dias)
│
├─ Logs\ # Logs de execução de cada script
│ ├─ cleanup_temp_*.log
│ ├─ rotate_logs_*.log
│ ├─ optimize_winsxs_*.log
│ └─ eventlog_maint_*.log
│
└─ Backups\ # Backups de logs de eventos (EVTX)
├─ System_YYYYMMDD.evtx
├─ Application_YYYYMMDD.evtx
└─ Security_YYYYMMDD.evtx
Step 6: Script de limpeza de Temp
Este script remove arquivos e pastas mais antigos que DaysToKeep dias em cada diretório listado em $TempPaths, registrando todos os resultados em um arquivo de log.
Os parâmetros DaysToKeep e LogPath podem ser sobrescritos na linha de comando.
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 rotação de logs
Arquivo de configuração de rotação (PSD1)
Este arquivo PSD1 define vários diretórios de destino e seus respectivos dias de retenção. Para adicionar um novo diretório de logs, basta incluir uma nova entrada.
log_rotation.psd1
@{
RotationTargets = @(
@{
Path = "C:\Logs\App1"
DaysToKeep = 7
},
@{
Path = "C:\Logs\App2"
DaysToKeep = 30
},
@{
Path = "<<LOG_PATH>>"
DaysToKeep = 7
}
)
}
Script de rotação de logs
Este script lê RotationTargets a partir do PSD1 e remove arquivos .log em cada caminho cujo LastWriteTime seja mais antigo que o limite calculado. Todas as ações são registradas em 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 de otimização do WinSxS
Este script mede o tamanho do diretório WinSxS antes e depois da limpeza e executa /StartComponentCleanup /ResetBase. Assim, é possível ver numericamente o ganho em espaço em disco.
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 manutenção de logs de eventos
Este script exporta os logs especificados (por padrão: System / Application / Security) para arquivos .evtx em um diretório de backup e, em seguida, limpa os logs originais. O arquivo de log registra todos os sucessos e falhas.
maintain_eventlogs.ps1
param(
[string]$LogPath = "<<LOG_PATH>>", # Diretório de logs (.log)
[string]$BackupPath = "<<BACKUP_PATH>>", # Diretório de backup EVTX
[string[]]$EventLogs = @("System", "Application", "Security")
)
# Criar diretório de logs, se necessário
if (-not (Test-Path $LogPath)) {
New-Item $LogPath -ItemType Directory -Force | Out-Null
}
# Criar diretório de backup, se necessário
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) {
# Gerar um nome de arquivo EVTX único por 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: Exemplos de registro no Agendador de Tarefas
A seguir, todos os scripts de manutenção são registrados usando schtasks.exe.
Para uma explicação detalhada das opções /SC, /D, /ST, /RU etc., consulte:
Gerenciamento do Agendador de Tarefas com schtasks.exe
Exemplo de tarefa diária de limpeza de Temp
Executa cleanup_temp.ps1 todos os dias às 2:00, removendo arquivos temporários mais antigos que 7 dias.
A tarefa é executada como <<ADMIN_USER>> com privilégios máximos (/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
Exemplo de tarefa diária de rotação de logs
Executa rotate_logs.ps1 todos os dias às 2:30 e rotaciona arquivos .log em vários diretórios com base na configuração PSD1.
Os dias de retenção são controlados apenas pelo arquivo 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
Exemplo de tarefa mensal de otimização do WinSxS
Executa optimize_winsxs.ps1 no dia 1 de cada mês às 3:00, realizando StartComponentCleanup /ResetBase com medição de tamanho.
Como não há rollback, agendar este script em uma janela de manutenção é obrigatório.
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
Exemplo de tarefa mensal de manutenção de logs de eventos
Executa maintain_eventlogs.ps1 no dia 1 de cada mês às 3:30, exportando logs como System / Application / Security para o diretório de backup e depois limpando esses logs.
Ajuste -EventLogs e -BackupPath conforme seus requisitos de auditoria.
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
Resumo
Este artigo apresentou uma abordagem para dividir a manutenção de disco no Windows Server em scripts específicos por objetivo, usando ainda um arquivo de configuração PSD1 para controlar a rotação de logs de forma flexível.
- Limpeza de Temp: execução diária, com dias de retenção configuráveis
- Rotação de logs: múltiplos caminhos e retenções definidos em PSD1
- Otimização do WinSxS: mensal, com registro da redução de tamanho
- Manutenção de logs de eventos: mensal, com backup em EVTX seguido de limpeza
O resultado é uma automação de manutenção robusta e extensível para ambientes de produção.
