Healthcheck Windows (Cleaner)
Notebook de PowerShell para healthchecks básicos y avanzados en Windows. Cada sección explica el objetivo, comando y cómo interpretar resultados.
Diagnósticos Básicos
Section titled “Diagnósticos Básicos”Objetivo: Detectar fallos recientes (hardware, drivers, servicios críticos) en el registro de eventos.
$Days = 7Get-WinEvent -FilterHashtable @{ LogName = 'System' Level = 2 # 2 = Error (crítico) StartTime = (Get-Date).AddDays(-$Days)} -MaxEvents 50 | Format-Table TimeCreated, Id, ProviderName, Message -AutoSizeQué observar:
- Errores repetidos (mismo Id + ProviderName) → patrón a investigar
- Controladores / disk / ntfs / storport → posible riesgo hardware
- Service Control Manager → servicios que no inician
Objetivo: Evitar degradación de rendimiento por falta de espacio.
Get-CimInstance -Class Win32_LogicalDisk -Filter 'DriveType = 3' | Select-Object DeviceID, @{N='SizeGB';E={[math]::Round($_.Size/1GB,1)}}, @{N='FreeGB';E={[math]::Round($_.FreeSpace/1GB,1)}}, @{N='PctFree';E={[math]::Round(($_.FreeSpace*100)/$_.Size,1)}} | Format-Table -AutoSizeUmbrales:
- ⚠️ Volúmenes < 20% libre → planificar limpieza
- 🔴 Disco C: con < 10 GB libre → prioridad alta
Objetivo: Verificar amenazas comunes con escaneo rápido.
Start-MpScan -ScanType QuickScanGet-MpThreatObjetivo: Detectar servicios automáticos que no están corriendo.
Get-Service -ErrorAction SilentlyContinue | Where-Object { $_.Status -ne 'Running' -and $_.StartType -eq 'Automatic' } | Sort-Object DisplayName | Format-Table Status, Name, DisplayName -AutoSizeStart-Service -Name <Nombre>Objetivo: Identificar consumo anómalo de RAM y fugas de memoria.
Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 10 Name, Id, @{N='MemMB';E={[math]::Round($_.WorkingSet64/1MB,2)}} | Format-Table -AutoSizeQué observar:
- Procesos desconocidos con alto uso
- Crecimiento continuo entre ejecuciones
- Apps que no deberían estar en servidor (Spotify, Discord)
Diagnósticos Avanzados
Section titled “Diagnósticos Avanzados”Objetivo: Detectar sobrecalentamiento que pueda causar throttling.
Get-CimInstance -Namespace root/wmi -ClassName MSAcpi_ThermalZoneTemperature 2>$null | Select-Object InstanceName, @{N='TempC';E={[math]::Round(($_.CurrentTemperature/10)-273.15,1)}}Get-PhysicalDisk | Select FriendlyName, MediaType, HealthStatus, @{N='TempC';E={$_.Temperature}} | Format-Table -AutoSizeUmbrales:
- ⚠️ CPU > 85°C sostenida → revisar pasta térmica
- ⚠️ NVMe > 70°C sostenida → riesgo vida útil
Objetivo: Anticipar fallos de disco revisando indicadores de salud.
Get-PhysicalDisk | Select FriendlyName, MediaType, HealthStatus, OperationalStatus, Size | Format-Table -AutoSizeGet-PhysicalDisk | ForEach-Object { $r = Get-StorageReliabilityCounter -PhysicalDisk $_ -ErrorAction SilentlyContinue [PSCustomObject]@{ Disk = $_.FriendlyName Wear = $r.Wear ReadErrors = $r.ReadErrorsTotal WriteErrors = $r.WriteErrorsTotal Temperature = $r.Temperature }} | Format-Table -AutoSizeAlertas:
- 🔴 HealthStatus ≠
Healthy - 🔴 Incremento de Read/WriteErrors entre chequeos
Objetivo: Detectar degradación de red que afecte servicios.
$targets = @( (Get-NetRoute -DestinationPrefix '0.0.0.0/0' | Sort-Object RouteMetric | Select-Object -First 1).NextHop, '8.8.8.8', '1.1.1.1', 'github.com')
$targets | ForEach-Object { $r = Test-Connection -ComputerName $_ -Count 4 -ErrorAction SilentlyContinue if ($r) { [PSCustomObject]@{ Host = $_ AvgMs = [math]::Round(($r | Measure-Object -Property ResponseTime -Average).Average, 2) Loss = 0 } } else { [PSCustomObject]@{ Host = $_; AvgMs = $null; Loss = 100 } }} | Format-Table -AutoSizeUmbrales:
- ⚠️ Gateway > 5-10 ms → congestión local
- ⚠️ Externa > 120 ms (antes < 40) → problema de ruta
- 🔴 Pérdida > 2% sostenida
Objetivo: Confirmar que el sistema está al día con parches de seguridad.
Get-HotFix | Sort-Object InstalledOn -Descending | Select -First 10 Source, Description, HotFixID, InstalledOn | Format-Table -AutoSize$last = (Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 1).InstalledOn[PSCustomObject]@{ UltimoParche = $last Dias = (New-TimeSpan -Start $last -End (Get-Date)).Days} | Format-ListAlerta: Más de 30 días sin parches → revisar ciclo de updates
Script de Reporte Automatizado
Section titled “Script de Reporte Automatizado”Genera un reporte Markdown consolidado:
$report = "# Healthcheck $(Get-Date -Format 'yyyy-MM-dd HH:mm')`n"
$report += "`n## Errores System (7d)`n"$report += (Get-WinEvent -FilterHashtable @{ LogName='System'; Level=2; StartTime=(Get-Date).AddDays(-7)} -MaxEvents 10 -ErrorAction SilentlyContinue | Select-Object TimeCreated, Id, ProviderName, Message | Out-String)
$report += "`n## Disco`n"$report += (Get-CimInstance Win32_LogicalDisk -Filter 'DriveType = 3' | Select DeviceID, @{N='Free%';E={[math]::Round(($_.FreeSpace*100)/$_.Size,1)}} | Out-String)
$report += "`n## Servicios Detenidos`n"$report += (Get-Service | Where-Object { $_.Status -ne 'Running' -and $_.StartType -eq 'Automatic' } | Select Status, Name | Out-String)
$report | Set-Content .\healthcheck_report.mdWrite-Host "✅ Reporte guardado en healthcheck_report.md"