Cada vez que te conectas por RDP a una máquina Windows solo para “echar un vistazo rápido”, pagas un impuesto invisible: latencia, cambio de contexto y la probabilidad real de hacer clic en lo incorrecto en el servidor equivocado. Las GUIs son geniales para demostraciones y terribles para la respuesta a incidentes. Durante una caída, una GUI es como una máquina tragamonedas: sigues tirando de la palanca esperando que la próxima ventana revele la verdad.
Los one-liners de PowerShell no se tratan de ser ingeniosos. Se trata de ser rápido, repetible y auditable. Transforman “creo que está bien” en “esto es lo que dice el sistema”. Úsalos a diario y dedicarás menos tiempo a hacer clic y más tiempo a tomar decisiones que resistan en un postmortem.
Por qué ganan los one-liners en producción
Un buen one-liner hace tres cosas: consulta el sistema de registro, formatea el resultado en algo con lo que puedas razonar y hace obvia la siguiente acción. Ese es todo el punto. No es una competición de sintaxis.
La versión GUI de las tareas comunes suele ser:
- Conectarse al host correcto (o al equivocado; aún no lo sabrás).
- Abrir el complemento correcto.
- Esperar a que cargue y renderice.
- Hacer clic, filtrar, ordenar, hacer clic otra vez.
- Tomar una captura de pantalla porque no puedes comparar fácilmente capturas.
La versión PowerShell es:
- Ejecutar un comando que devuelve objetos estructurados.
- Pasar por la tubería para ordenar, filtrar, agrupar.
- Guardar la salida (o exportarla) para que puedas compararla más tarde.
Además: cada vez que copias/pegas “lo que viste en la GUI” en un ticket, estás traduciendo. La traducción introduce errores. Los datos más seguros son los que no reinterpretas.
Idea parafraseada de Gene Kim (autor sobre DevOps/operaciones): las mejoras provienen de acortar los ciclos de retroalimentación y hacer el trabajo visible.
Los one-liners hacen ambas cosas cuando los usas de forma consistente.
Broma #1: Hacer clic por el Administrador del servidor durante un incidente es como depurar con una linterna: técnicamente posible, pero te vas a tropezar con algo.
Hechos y contexto histórico (breve, útil)
- PowerShell se lanzó en 2006 como “Monad”, construido sobre objetos .NET en vez de flujos de texto plano. Por eso canaliza objetos, no cadenas.
- WMI es anterior a PowerShell; muchas comprobaciones “modernas” de PowerShell aún envuelven clases WMI/CIM que existen desde los años 90.
- WinRM se convirtió en el caballo de batalla remoto para el remoting de PowerShell, acercando las operaciones de Windows a flujos de trabajo tipo SSH — excepto con más Kerberos y menos sorpresas agradables.
- PowerShell 5.1 se distribuyó con Windows 10/Server 2016 y sigue siendo el predeterminado en muchos servidores; PowerShell 7+ es separado y multiplataforma.
- Get-WmiObject es legado;
Get-CimInstancees el patrón más reciente (basado en WS-Man), generalmente más compatible con firewall y remoting. - Los contadores de rendimiento son antiguos pero valiosos; siguen siendo una de las formas más fiables de ver presión de CPU, memoria, disco y red en Windows.
- Los registros de eventos son lo más cercano a una caja negra para Windows: son imperfectos, pero cuando se usan con filtros superan el “te juro que pasó”.
- Hyper-V y Storage Spaces apostaron fuertemente por PowerShell desde temprano; muchas acciones de GUI son literalmente envoltorios alrededor de cmdlets.
- Group Policy y Active Directory tienen cmdlets que reducen los “ajustes misteriosos” al convertir el estado de la política en datos consultables.
One-liners diarios: tareas, salidas y la decisión que tomas
A continuación hay comandos prácticos y ejecutables. Cada uno incluye (a) qué hace, (b) qué significa la salida y (c) la decisión que tomas a partir de ella. Ejecútalos localmente o de forma remota (muchos admiten -ComputerName o funcionan vía remoting).
Nota sobre los bloques de código: Los muestro como si se ejecutaran desde un prompt de shell. En la práctica los ejecutarás en PowerShell. Los comandos son PowerShell reales.
1) Comprobar espacio libre en disco (rápido, ordenable, sin el Explorador)
cr0x@server:~$ powershell -NoProfile -Command "Get-Volume | Where-Object DriveLetter | Select-Object DriveLetter,FileSystemLabel,@{n='SizeGB';e={[math]::Round($_.Size/1GB,1)}},@{n='FreeGB';e={[math]::Round($_.SizeRemaining/1GB,1)}},@{n='FreePct';e={[math]::Round(($_.SizeRemaining/$_.Size)*100,1)}} | Sort-Object FreePct | Format-Table -Auto"
DriveLetter FileSystemLabel SizeGB FreeGB FreePct
----------- -------------- ------ ------ -------
C OS 127.9 11.8 9.2
E Logs 500.0 210.5 42.1
F Data 2048.0 1530.2 74.7
Qué significa: FreePct es el primer indicador de triaje. Por debajo de ~10–15% en volúmenes del sistema, deberías asumir que las cosas se romperán de formas extrañas (parches, archivos temporales, rotación de logs, volcados de crash).
Decisión: Si C: está bajo, deja de “optimizar” y comienza a liberar espacio: limpiar caches conocidos, rotar logs, mover volcados o ampliar el volumen. Si un volumen de datos está bajo, busca los mayores consumidores a continuación.
2) Encontrar directorios más grandes (la respuesta a “qué se comió mi disco”)
cr0x@server:~$ powershell -NoProfile -Command "Get-ChildItem -Directory 'E:\' -Force | ForEach-Object { $s=(Get-ChildItem $_.FullName -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object Length -Sum).Sum; [pscustomobject]@{Path=$_.FullName; SizeGB=[math]::Round($s/1GB,2)} } | Sort-Object SizeGB -Descending | Select-Object -First 10 | Format-Table -Auto"
Path SizeGB
---- ------
E:\IISLogs 96.41
E:\App\Cache 51.08
E:\App\Temp 23.77
E:\Windows\Installer 12.30
Qué significa: Esto es costoso en árboles grandes, pero es honesto. Úsalo cuando necesites hechos, no corazonadas.
Decisión: Si los logs dominan, arregla la retención/rotación. Si cache/temp domina, confirma si es seguro limpiar y por qué está creciendo. Si Windows\Installer crece, no borres al azar—limpia mediante métodos soportados.
3) Procesos con más CPU (Task Manager, pero scriptable)
cr0x@server:~$ powershell -NoProfile -Command "Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 Name,Id,CPU,WorkingSet64 | Format-Table -Auto"
Name Id CPU WorkingSet64
---- -- --- -----------
sqlservr 2440 8123.54 9126807552
w3wp 4012 1022.10 785334272
MsMpEng 1780 331.92 402653184
Qué significa: CPU aquí es tiempo de CPU acumulado desde el inicio del proceso, no “porcentaje actual”. Responde a “qué ha estado consumiendo CPU a lo largo del tiempo”, que a menudo es lo que realmente necesitas.
Decisión: Si el mismo proceso domina y el rendimiento está actualmente mal, pasa a contadores de rendimiento para CPU en tiempo real y colas. Si es un escáner AV, considera exclusiones (con cuidado) o programar escaneos.
4) Presión de CPU en tiempo real y cola de ejecución (evita adivinar)
cr0x@server:~$ powershell -NoProfile -Command "Get-Counter '\Processor(_Total)\% Processor Time','\System\Processor Queue Length' -SampleInterval 2 -MaxSamples 5 | Select-Object -ExpandProperty CounterSamples | Select-Object Path,CookedValue | Format-Table -Auto"
Path CookedValue
---- -----------
\\SERVER\processor(_total)\% processor time 87.12
\\SERVER\system\processor queue length 14
\\SERVER\processor(_total)\% processor time 92.44
\\SERVER\system\processor queue length 18
Qué significa: Sustentar un alto % Processor Time más una cola que se mantiene elevada sugiere contención de CPU. La cola es especialmente reveladora en máquinas con pocos núcleos.
Decisión: Si la cola se mantiene alta, identifica la carga (procesos principales, tareas programadas, AV, backup). Si es una máquina virtual, comprueba la contención en el host también. No “añadas vCPUs” sin medir el ready time del host (otro conjunto de herramientas), pero trata la cola sostenida como una señal real.
5) Presión de memoria: bytes disponibles y actividad de paginación
cr0x@server:~$ powershell -NoProfile -Command "Get-Counter '\Memory\Available MBytes','\Memory\Pages/sec' -SampleInterval 2 -MaxSamples 5 | Select-Object -ExpandProperty CounterSamples | Select-Object Path,CookedValue | Format-Table -Auto"
Path CookedValue
---- -----------
\\SERVER\memory\available mbytes 312.00
\\SERVER\memory\pages/sec 86.50
\\SERVER\memory\available mbytes 280.00
\\SERVER\memory\pages/sec 95.00
Qué significa: Pocos MB disponibles más pages/sec sostenidos sugiere paginación activa. La paginación no es mala per se; la paginación sostenida bajo carga sí lo es.
Decisión: Si la paginación es alta durante quejas de latencia, o (a) necesitas más RAM, (b) hay una fuga de memoria, o (c) hay una caché que creció porque tu conjunto de trabajo aumentó. Valida con working sets de procesos y telemetría de la aplicación.
6) Latencia de disco y longitud de cola (los ingenieros de almacenamiento viven aquí)
cr0x@server:~$ powershell -NoProfile -Command "Get-Counter '\PhysicalDisk(_Total)\Avg. Disk sec/Read','\PhysicalDisk(_Total)\Avg. Disk sec/Write','\PhysicalDisk(_Total)\Current Disk Queue Length' -SampleInterval 2 -MaxSamples 5 | Select-Object -ExpandProperty CounterSamples | Select-Object Path,CookedValue | Format-Table -Auto"
Path CookedValue
---- -----------
\\SERVER\physicaldisk(_total)\avg. disk sec/read 0.045
\\SERVER\physicaldisk(_total)\avg. disk sec/write 0.112
\\SERVER\physicaldisk(_total)\current disk queue length 23
Qué significa: Lecturas de 45ms y escrituras de 112ms con una cola de 23 no es “aceptable”. Para muchos workloads de servidor, quieres latencias de milisegundos de un solo dígito. Hay excepciones, pero deben ser intencionales.
Decisión: Si latencia y cola son altas, identifica el volumen ocupado y luego el proceso que lo ocupa. En VMs, confirma si es problema del invitado o del host. No persigas CPU si el disco está ahogándose.
7) ¿Quién está martillando el disco? (E/S por proceso)
cr0x@server:~$ powershell -NoProfile -Command "Get-Process | Select-Object Name,Id,@{n='ReadMB';e={[math]::Round($_.IOReadBytes/1MB,1)}},@{n='WriteMB';e={[math]::Round($_.IOWriteBytes/1MB,1)}} | Sort-Object WriteMB -Descending | Select-Object -First 10 | Format-Table -Auto"
Name Id ReadMB WriteMB
---- -- ------ -------
sqlservr 2440 5120.3 9032.8
backup 3112 120.1 2201.4
w3wp 4012 980.7 610.2
Qué significa: Son contadores acumulativos. Apuntan rápidamente a los sospechosos habituales: motores de base de datos, agentes de backup, indexación, antivirus, logging descontrolado.
Decisión: Si backup o AV dominan durante horas de negocio, arregla la programación. Si el logging domina, corrige el nivel de logging o envíalo a otro volumen.
8) Comprobar qué puertos están escuchando (la GUI no está invitada)
cr0x@server:~$ powershell -NoProfile -Command "Get-NetTCPConnection -State Listen | Select-Object LocalAddress,LocalPort,OwningProcess | Sort-Object LocalPort | Select-Object -First 20 | Format-Table -Auto"
LocalAddress LocalPort OwningProcess
------------ --------- -------------
0.0.0.0 80 4012
0.0.0.0 135 968
0.0.0.0 443 4012
0.0.0.0 3389 1156
Qué significa: Esto responde “qué está realmente escuchando”, no “qué creemos que debería estar corriendo”. Empareja esto con nombres de procesos a continuación.
Decisión: Si un puerto crítico no está escuchando, investiga el servicio/aplicación. Si un puerto inesperado está escuchando, tienes deriva o compromiso—trátalo en serio.
9) Mapear puertos escuchando a nombres de proceso (hazlo accionable)
cr0x@server:~$ powershell -NoProfile -Command "Get-NetTCPConnection -State Listen | ForEach-Object { $p=Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue; [pscustomobject]@{Port=$_.LocalPort; Process=$p.Name; PID=$_.OwningProcess; Address=$_.LocalAddress} } | Sort-Object Port | Format-Table -Auto"
Port Process PID Address
---- ------- --- -------
80 w3wp 4012 0.0.0.0
135 svchost 968 0.0.0.0
443 w3wp 4012 0.0.0.0
3389 TermService 1156 0.0.0.0
Qué significa: Ahora “el puerto 443 está caído” se convierte en “w3wp no está corriendo”, que es la diferencia entre pánico y reparación.
Decisión: Si el PID no es el esperado, comprueba la configuración del servicio, bindings de IIS o parámetros de lanzamiento de la aplicación. Si es desconocido, no te encoges de hombros—identifica la ruta del binario.
10) Verificar que un servicio de Windows esté en ejecución (y por qué no lo está)
cr0x@server:~$ powershell -NoProfile -Command "Get-Service -Name 'Spooler','W32Time','WinRM' | Select-Object Name,Status,StartType | Format-Table -Auto"
Name Status StartType
---- ------ ---------
Spooler Running Automatic
W32Time Running Automatic
WinRM Running Automatic
Qué significa: Esto es higiene básica. Si WinRM está apagado, tu jornada de operaciones remotas se convierte en un día de viaje.
Decisión: Si un servicio crítico está detenido, revisa cambios recientes y los registros del sistema antes de reiniciarlo. Reinicios a ciegas pueden ocultar evidencia y repetir fallos.
11) Extraer los últimos 50 errores del sistema (Event Viewer es un laberinto)
cr0x@server:~$ powershell -NoProfile -Command "Get-WinEvent -FilterHashtable @{LogName='System'; Level=2} -MaxEvents 50 | Select-Object TimeCreated,Id,ProviderName,Message | Format-Table -Wrap"
TimeCreated Id ProviderName Message
----------- -- ------------ -------
02/05/2026 09:14:02 11 Disk The driver detected a controller error on \Device\Harddisk2\DR2.
02/05/2026 09:11:47 7031 Service Control Manager The SQLAgent$INST service terminated unexpectedly...
Qué significa: Level=2 es “Error.” Buscas patrones: errores de disco/controlador, caídas de servicios, fallos de sincronización de tiempo, reinicios de red.
Decisión: Errores de disco/controlador te desplazan de “depuración de aplicación” a “integridad de datos y ruta de hardware”. Las caídas de servicio te mueven a “qué cambió” y volcados de crash.
12) Extraer errores de aplicación para un proveedor específico (triaje dirigido)
cr0x@server:~$ powershell -NoProfile -Command "Get-WinEvent -FilterHashtable @{LogName='Application'; ProviderName='Application Error'} -MaxEvents 20 | Select-Object TimeCreated,Id,Message | Format-Table -Wrap"
TimeCreated Id Message
----------- -- -------
02/05/2026 09:12:10 1000 Faulting application name: w3wp.exe...
Qué significa: Esta es la fuente “por qué se estrelló”. Verás módulos con fallos, códigos de excepción y nombres de aplicaciones.
Decisión: Si el mismo módulo falla repetidamente tras un parche o cambio de configuración, revierte o actualiza. Si es aleatorio, sospecha corrupción de memoria, controladores defectuosos o dependencias inestables.
13) Comprobar reinicios recientes y por qué (la verdad está en los logs)
cr0x@server:~$ powershell -NoProfile -Command "Get-WinEvent -FilterHashtable @{LogName='System'; Id=1074} -MaxEvents 10 | Select-Object TimeCreated,Message | Format-Table -Wrap"
TimeCreated Message
----------- -------
02/04/2026 23:01:12 The process C:\Windows\System32\svchost.exe (SERVER) has initiated the restart...
Qué significa: El evento ID 1074 suele registrar reinicios iniciados por un usuario o proceso e incluye la cadena de razón si se proporcionó.
Decisión: Si los reinicios son inesperados, deja de tratar la disponibilidad como clima aleatorio. Relaciona los reinicios con ventanas de parcheo, automatizaciones u operadores. Arregla el proceso, no el síntoma.
14) Comprobar actualizaciones instaladas (nivel de parches sin hacer clic)
cr0x@server:~$ powershell -NoProfile -Command "Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 10 HotFixID,InstalledOn,Description | Format-Table -Auto"
HotFixID InstalledOn Description
------- ----------- -----------
KB5034765 02/02/2026 Update
KB5034123 01/15/2026 Security Update
Qué significa: Confirmación rápida de la vigencia de parches. No es perfecto (algunos mecanismos de actualización no aparecen claramente), pero es un primer paso sólido.
Decisión: Si un bug se correlaciona con un KB reciente, ahora tienes una hipótesis creíble de rollback. Si un servidor está muy atrasado, deja de fingir que está “estable”; simplemente no está parcheado.
15) Validar resolución DNS y tipo de registro (evita el teatro de “la red está caída”)
cr0x@server:~$ powershell -NoProfile -Command "Resolve-DnsName -Name 'app01.corp.local' -Type A | Select-Object Name,Type,IPAddress | Format-Table -Auto"
Name Type IPAddress
---- ---- ---------
app01.corp.local A 10.40.12.21
Qué significa: Si esto falla o devuelve la IP incorrecta, la mitad de tu “incidente de aplicación” es en realidad resolución de nombres.
Decisión: IP incorrecta significa DNS antiguo o registro erróneo; corrige expectativas de TTL, integración DHCP/DNS o registros manuales. Sin respuesta significa investigar servidores DNS, reenvíos o firewall.
16) Probar un servicio TCP de extremo a extremo (ping no es un health check)
cr0x@server:~$ powershell -NoProfile -Command "Test-NetConnection -ComputerName 'app01.corp.local' -Port 443 | Select-Object ComputerName,RemotePort,TcpTestSucceeded,SourceAddress | Format-List"
ComputerName : app01.corp.local
RemotePort : 443
TcpTestSucceeded : True
SourceAddress : 10.40.10.55
Qué significa: Responde “puedo establecer una conexión TCP desde aquí hacia allá”. No valida certificados TLS ni la corrección de la aplicación, pero reduce rápidamente el campo del problema.
Decisión: Si TcpTestSucceeded es false, verifica reglas de firewall, ruteo, estado del listener y balanceadores. Si es true, sube en la pila: TLS, HTTP, auth, logs de la app.
17) Encontrar tareas programadas fallidas (los saboteadores silenciosos)
cr0x@server:~$ powershell -NoProfile -Command "Get-ScheduledTask | Get-ScheduledTaskInfo | Where-Object {$_.LastTaskResult -ne 0} | Sort-Object LastRunTime -Descending | Select-Object -First 15 TaskName,LastRunTime,LastTaskResult | Format-Table -Auto"
TaskName LastRunTime LastTaskResult
-------- ----------- --------------
DailyLogRotate 02/05/2026 01:00:01 2147942401
BackupSnapshot 02/05/2026 02:00:03 1
Qué significa: Resultados distintos de cero indican fallo. El código numérico suele corresponder a “archivo no encontrado”, “acceso denegado”, etc.
Decisión: Si tareas de mantenimiento fallan, espera incidentes por disco lleno y muerte por mil cortes de rendimiento. Arregla permisos, rutas y cuentas de servicio antes del próximo pico.
18) Comprobar shares SMB y quién está conectado (realidad de servidores de archivos)
cr0x@server:~$ powershell -NoProfile -Command "Get-SmbShare | Select-Object Name,Path,Description | Format-Table -Auto"
Name Path Description
---- ---- -----------
Finance D:\Finance Finance share
Profiles E:\Profiles User profiles
cr0x@server:~$ powershell -NoProfile -Command "Get-SmbSession | Select-Object ClientComputerName,ClientUserName,NumOpens,Dialect | Sort-Object NumOpens -Descending | Select-Object -First 10 | Format-Table -Auto"
ClientComputerName ClientUserName NumOpens Dialect
------------------ -------------- -------- -------
WS123 CORP\j.smith 42 3.1.1
Qué significa: Así confirmas “¿alguien está usando el share ahora?” antes de mantenimiento, y ayuda a identificar un cliente que causa tormentas de locks.
Decisión: Si un cliente tiene un número absurdo de opens, investiga esa estación/aplicación. Si necesitas reiniciar un share, coordina con los usuarios en vez de arruinarles el día.
19) Comprobación de permisos: ¿quién tiene acceso a una carpeta?
cr0x@server:~$ powershell -NoProfile -Command "(Get-Acl 'D:\Finance').Access | Select-Object IdentityReference,FileSystemRights,AccessControlType,IsInherited | Format-Table -Auto"
IdentityReference FileSystemRights AccessControlType IsInherited
----------------- ---------------- ----------------- -----------
CORP\Finance-Users Modify, Synchronize Allow True
CORP\Domain Admins FullControl Allow True
Qué significa: Muestra entradas efectivas de ACL, incluida la herencia. Es la diferencia entre “debería funcionar” y “funciona”.
Decisión: Si falta acceso, arregla membresías de grupo o herencia en el nivel correcto. Evita ACLs únicas por usuario a menos que disfrutes de la arqueología futura.
20) Remoto: ejecutar una comprobación de salud en varios servidores (flota, no mascotas)
cr0x@server:~$ powershell -NoProfile -Command "$servers='web01','web02','web03'; Invoke-Command -ComputerName $servers -ScriptBlock { [pscustomobject]@{ ComputerName=$env:COMPUTERNAME; UptimeDays=[math]::Round((New-TimeSpan -Start (Get-CimInstance Win32_OperatingSystem).LastBootUpTime -End (Get-Date)).TotalDays,1); FreeC=[math]::Round((Get-PSDrive C).Free/1GB,1) } } | Format-Table -Auto"
ComputerName UptimeDays FreeC
------------ --------- -----
WEB01 12.4 18.7
WEB02 2.1 6.3
WEB03 56.0 22.9
Qué significa: Un comando, tres máquinas, datos consistentes. Además: WEB02 tiene poco espacio libre y se reinició recientemente. Esa correlación rara vez es accidental.
Decisión: Prioriza el outlier. No promediess y te confíes en la complacencia. Arregla WEB02 primero y luego pregunta por qué se comporta diferente.
Broma #2: La GUI dice “No responde” como si fuera un límite personal. El servidor lo dice porque está en llamas.
Guía de diagnóstico rápido: qué comprobar primero/segundo/tercero
Esta es la secuencia que uso cuando alguien dice “la app está lenta” o “el servidor se está muriendo” y el único detalle que tienes es un hostname y pavor. El objetivo no es resolver todo en 60 segundos; el objetivo es encontrar la clase de cuello de botella para dejar de adivinar.
Primero: confirma que la queja es real y está acotada
- Desde el lado del cliente: ¿puedes conectarte al puerto del servicio?
cr0x@server:~$ powershell -NoProfile -Command "Test-NetConnection -ComputerName 'app01.corp.local' -Port 443 | Select-Object TcpTestSucceeded,RemoteAddress,RemotePort | Format-List" TcpTestSucceeded : True RemoteAddress : 10.40.12.21 RemotePort : 443Interpretación: Si TCP falla, es red/listener/LB/seguridad. Si TCP tiene éxito, avanza hacia adentro.
- En el servidor: ¿está escuchando el puerto relevante y es propiedad del proceso correcto?
cr0x@server:~$ powershell -NoProfile -Command "Get-NetTCPConnection -State Listen -LocalPort 443 | ForEach-Object { $p=Get-Process -Id $_.OwningProcess; [pscustomobject]@{Port=$_.LocalPort; Process=$p.Name; PID=$p.Id} } | Format-Table -Auto" Port Process PID ---- ------- --- 443 w3wp 4012Interpretación: Sin listener significa que la app está caída. Proceso equivocado significa mala configuración o algo peor.
Segundo: clasifica el cuello de botella (CPU, memoria, disco, red o “app”)
- Presión de CPU: % processor time + cola de procesador.
cr0x@server:~$ powershell -NoProfile -Command "Get-Counter '\Processor(_Total)\% Processor Time','\System\Processor Queue Length' -SampleInterval 2 -MaxSamples 3 | Select-Object -ExpandProperty CounterSamples | Select-Object Path,CookedValue | Format-Table -Auto" Path CookedValue ---- ----------- \\SERVER\processor(_total)\% processor time 91.33 \\SERVER\system\processor queue length 16Decisión: Si la CPU está al máximo con colas, identifica el proceso caliente y qué lo desencadenó (deploy, job, scan, tormenta de reintentos).
- Presión de memoria: MB disponibles + pages/sec.
cr0x@server:~$ powershell -NoProfile -Command "Get-Counter '\Memory\Available MBytes','\Memory\Pages/sec' -SampleInterval 2 -MaxSamples 3 | Select-Object -ExpandProperty CounterSamples | Select-Object Path,CookedValue | Format-Table -Auto" Path CookedValue ---- ----------- \\SERVER\memory\available mbytes 190.00 \\SERVER\memory\pages/sec 120.00Decisión: Si estás paginando mucho, espera latencia en todas partes. Captura datos de memoria de procesos; considera un reinicio controlado solo después de recopilar evidencia.
- Presión de disco: latencia + cola.
cr0x@server:~$ powershell -NoProfile -Command "Get-Counter '\PhysicalDisk(_Total)\Avg. Disk sec/Read','\PhysicalDisk(_Total)\Avg. Disk sec/Write','\PhysicalDisk(_Total)\Current Disk Queue Length' -SampleInterval 2 -MaxSamples 3 | Select-Object -ExpandProperty CounterSamples | Select-Object Path,CookedValue | Format-Table -Auto" Path CookedValue ---- ----------- \\SERVER\physicaldisk(_total)\avg. disk sec/read 0.060 \\SERVER\physicaldisk(_total)\avg. disk sec/write 0.140 \\SERVER\physicaldisk(_total)\current disk queue length 27Decisión: Si el disco está mal, deja de buscar “consultas lentas” hasta confirmar que el almacenamiento no es el limitador. Latencia aguas arriba suele significar problema aguas abajo.
Tercero: decide “mitigar ahora” versus “investigar”
- Mitigar ahora cuando el impacto al usuario es severo y la solución es reversible: parar un job descontrolado, limitar una cola, conmutar por error, añadir capacidad temporal, mover logs.
- Investigar primero cuando la acción destruye evidencia: reinicios, reinicios de servicio, borrar logs, eliminar árboles temporales sin snapshots.
Usa los comandos anteriores para apoyar esa decisión y luego escribe lo que viste. Si no puedes explicar tu cadena de acciones más tarde, no operaste realmente—actuaste.
Tres mini-historias corporativas (qué salió mal, qué nos salvó)
Mini-historia 1: el incidente causado por una suposición equivocada
Heredamos un servidor de archivos Windows que “nunca tenía problemas”. La creencia compartida del equipo era que las alertas de disco detectarían cualquier cosa seria. El monitoreo alertó—eventualmente. El problema fue la suposición de que “espacio en disco” significaba “espacio libre” y que eso era todo lo que importaba.
Una mañana de lunes llegó una ola de tickets: perfiles itinerantes fallando, procesamiento de GPO lento, aplicaciones que se caían aleatoriamente cuando los usuarios iniciaban sesión. El on-call hizo lo clásico: RDP, abrir el Explorador, ver que C: tenía algunos GB libres y declarar “el disco no está lleno”. Luego reiniciaron un par de servicios. Parecía productivo. No sirvió de nada.
Ejecutamos one-liners: espacio libre en volúmenes (más o menos bien), luego logs de eventos (no bien). El log System tenía errores de disco/controlador y advertencias NTFS. El disco no estaba lleno; estaba enfermo. La latencia se disparaba, las escrituras se bloqueaban y el servidor de archivos estaba en efecto con I/O a cámara lenta.
La suposición equivocada fue sutil: “el espacio es el único problema de disco”. La salud del disco no es una variable única; es latencia, colas, tasas de error y estabilidad de la ruta. Cuando el almacenamiento empieza a fallar, Windows no siempre te da un pop-up amistoso. Te da timeouts y riesgo de corrupción.
La solución no fue un reinicio heroico. Failover de cargas, implicar al equipo de almacenamiento y reemplazar una ruta HBA defectuosa. La lección quedó: las comprobaciones de capacidad son necesarias; las comprobaciones de comportamiento del disco previenen desastres.
Mini-historia 2: la optimización que salió mal
Un ingeniero bienintencionado quería búsquedas de logs más rápidas. Activó logging verborreico en la aplicación y luego escribió una tarea programada para comprimir logs cada hora y moverlos a un share central. El plan sonaba razonable: archivos más pequeños, troubleshooting centralizado, menos uso de disco.
En producción se convirtió en una caída lenta. El job de compresión se lanzaba en la hora en punto en cada servidor—al mismo tiempo. La CPU se disparó, escrituras en disco se inflaron y el share central quedó saturado. El rendimiento de metadatos del share se desplomó porque miles de archivos se creaban, renombraban y eliminaban en ráfagas.
Los usuarios no se quejaron de “compresión de logs”. Se quejaron de que la app “se cuelga cada hora por unos minutos”. Ese síntoma está hecho a medida para el diagnóstico erróneo. La gente culpó GC, locks de BD y jitter de red. El verdadero culpable fue una “optimización” que creó contención sincronizada.
Lo demostramos con dos comprobaciones rápidas: longitud de cola de disco y E/S por proceso. El proceso de compresión no era el mayor consumidor de CPU todo el día, pero dominaba la E/S de escritura durante la ventana exacta de las quejas. Ese es el tipo de evidencia que zanja discusiones.
Lo arreglamos espaciando los horarios con jitter, reduciendo la verbosidad y cambiando el pipeline: comprimir una vez al día fuera del host, no cada hora en cada nodo. Las optimizaciones que ignoran patrones de contención no son optimizaciones; son denegación de servicio distribuida con mejores intenciones.
Mini-historia 3: la práctica aburrida pero correcta que salvó el día
Un equipo distinto ejecutaba una práctica pequeña pero disciplinada: cada mañana ejecutaban un corto “latido de servidor” contra su flota. Uptime, espacio libre, fecha del último parche y errores principales del log System. No lo hacían por amor a los dashboards. Lo hacían porque odiaban las sorpresas.
Un martes el latido marcó un solo servidor con una combinación extraña: espacio en E: cayendo rápido, fallos en tareas programadas y advertencias repetidas de un agente de backup. Nadie se quejaba aún. Ese es el punto clave: el sistema susurró antes de gritar.
Investigaron los fallos de la tarea programada y descubrieron que la tarea de rotación de logs empezó a fallar tras un cambio de permisos. Los logs se acumulaban, el backup fallaba por directorios de logs gigantes y el volumen se proyectaba a llenarse en 24 horas.
Arreglaron el ACL, ejecutaron la rotación manual una vez y validaron que la tarea programada terminó con éxito. El servidor nunca llegó a 0 bytes libres, el backup se recuperó y el negocio no se enteró.
Esto no es sexy. No gana premios de arquitectura. Gana el sueño del on-call. La práctica aburrida no fue el script; fue el hábito de mirar las mismas señales cada día y tratar las desviaciones como reales.
Errores comunes: síntomas → causa raíz → arreglo
1) “El servidor está lento” pero la CPU parece bien
Síntoma: Utilización de CPU moderada, pero usuarios ven timeouts y bloqueos.
Causa raíz: Latencia/colade disco o presión de paginación es el cuello de botella. La CPU está esperando, no trabajando.
Arreglo: Revisa contadores de disco y memoria primero, no las sensaciones del Task Manager.
cr0x@server:~$ powershell -NoProfile -Command "Get-Counter '\PhysicalDisk(_Total)\Avg. Disk sec/Read','\PhysicalDisk(_Total)\Current Disk Queue Length','\Memory\Pages/sec' -SampleInterval 2 -MaxSamples 3 | Select-Object -ExpandProperty CounterSamples | Select-Object Path,CookedValue | Format-Table -Auto"
Path CookedValue
---- -----------
\\SERVER\physicaldisk(_total)\avg. disk sec/read 0.080
\\SERVER\physicaldisk(_total)\current disk queue length 31
\\SERVER\memory\pages/sec 110
2) “El puerto está abierto” porque ping funciona
Síntoma: Alguien insiste que el servicio es accesible porque ICMP responde.
Causa raíz: Ping prueba ICMP, no la accesibilidad de la aplicación. Firewalls, balanceadores y listeners no se preocupan por tu ping exitoso.
Arreglo: Prueba el puerto TCP real desde la red del cliente real.
cr0x@server:~$ powershell -NoProfile -Command "Test-NetConnection -ComputerName 'db01.corp.local' -Port 1433 | Select-Object TcpTestSucceeded,RemoteAddress,RemotePort | Format-List"
TcpTestSucceeded : False
RemoteAddress : 10.40.20.10
RemotePort : 1433
3) “El servicio está en ejecución” pero la app sigue caída
Síntoma: Get-Service dice Running; los usuarios aún no pueden conectarse.
Causa raíz: El servicio está vivo pero no está escuchando, está atascado o enlazado a la interfaz/puerto equivocado. O una dependencia (cert, backend) está rota.
Arreglo: Valida el listener y mapea al proceso; revisa errores en el log de Aplicación.
cr0x@server:~$ powershell -NoProfile -Command "Get-NetTCPConnection -State Listen -LocalPort 443 | Measure-Object | Select-Object Count"
Count
-----
0
4) “Limpamos espacio” y ahora la app no arranca
Síntoma: Después de borrar “basura”, fallan servicios, instaladores o parches.
Causa raíz: Alguien borró archivos que no eran basura (cache de instalador, estado de app, bases de datos, backups de configuración de IIS).
Arreglo: Sé específico: identifica la fuente de crecimiento, corrige la retención y borra solo objetivos seguros. Si debes borrar, toma snapshot primero (snapshot de VM o shadow copy según política).
5) Remoting funciona a algunos servidores pero no a otros
Síntoma: Invoke-Command falla intermitentemente en la flota.
Causa raíz: WinRM deshabilitado, reglas de firewall diferentes, fallos de resolución DNS o configuración de hosts no confiables.
Arreglo: Estandariza: asegura que el servicio WinRM esté en ejecución, que las reglas de firewall sean consistentes y que el DNS sea correcto. Evita poner “TrustedHosts = *” como parche rápido en producción.
6) Ordenar la salida parece incorrecto
Síntoma: Ordenas por una columna y el orden es absurdo (por ejemplo, “100” antes que “9”).
Causa raíz: Formateaste demasiado pronto; convertiste objetos en cadenas con Format-Table antes de ordenar.
Arreglo: Ordena objetos primero, formatea al final.
Listas de verificación / plan paso a paso
Rutina diaria de operaciones de 10 minutos (hazlo, no lo debatas)
- Chequeo de espacio: encuentra volúmenes bajo 15% libre; crea un ticket antes de que sea urgente.
- Escaneo de errores: últimos 50 errores del System; identifica repeticiones (disco, resets de NIC, caídas de servicios).
- Sanidad de parches: confirma hotfixes recientes; marca máquinas que se desvían.
- Fallas de tareas: tareas programadas con resultados distintos de cero; arregla las aburridas primero.
- Chequeo de outliers: ejecuta el mismo one-liner en la flota y busca el servidor raro.
Lista de verificación de respuesta a incidentes (primeros 15 minutos)
- Confirmar alcanzabilidad:
Test-NetConnectional puerto del servicio desde un segmento de red relevante. - Confirmar listener/proceso:
Get-NetTCPConnection+ mapeo a proceso. - Clasificar cuello de botella: cola de CPU, paginación de memoria, latencia/cola de disco.
- Capturar evidencia: procesos principales, slice de logs de eventos, muestras de contadores.
- Mitigar de forma segura: solo después de poder justificar la acción con datos observados.
Lista de verificación para verificación de cambios (después de despliegues/parches)
- Confirmar estado de servicios: servicios esperados en ejecución, tipos de inicio correctos.
- Confirmar puertos: puertos esperados escuchando, propiedad de binarios esperados.
- Confirmar logs: escanear errores de Application y System desde el tiempo de despliegue.
- Confirmar rendimiento: comparar instantáneas de contadores (latencia, colas) con la línea base.
Preguntas frecuentes
1) ¿Debo usar Windows PowerShell 5.1 o PowerShell 7?
Usa 5.1 cuando necesites máxima compatibilidad con módulos antiguos en Windows Server. Usa 7 cuando controles el entorno y quieras características modernas y paridad multiplataforma. En empresas mixtas acabarás usando ambos.
2) ¿Por qué sigues usando contadores de rendimiento en vez de solo ver procesos “top”?
Porque los contadores te dicen presión (colado, latencia, paginación) mientras que las listas de procesos te dicen atribución. Necesitas ambos. Si solo miras procesos puedes perder la clase real de cuello de botella por completo.
3) ¿Está muerto Get-WmiObject?
No está muerto, solo es legado. Prefiere Get-CimInstance para patrones de scripting más nuevos, especialmente con remoting. Pero en la vida real seguirás viendo WMI en scripts de terceros y de proveedores.
4) ¿Por qué algunos contadores muestran números que no coinciden con lo que veo en el Administrador de tareas?
Muestreo y definiciones difieren. Task Manager a menudo muestra valores instantáneos o promediados; los contadores pueden muestrearse en intervalos distintos y representar modelos de cálculo diferentes. Haz explícito tu intervalo de muestreo y toma múltiples muestras.
5) ¿Puedo ejecutar estos one-liners contra servidores remotos sin RDP?
Sí, con remoting de PowerShell (Invoke-Command) cuando WinRM esté configurado. Para algunas comprobaciones de red también puedes consultar desde tu propia máquina (p. ej., Test-NetConnection). Estandariza WinRM pronto; compensa cada semana.
6) ¿Cómo evito problemas de “formatear demasiado pronto”?
Regla: realiza todo el filtrado/ordenado/agrupado mientras la tubería todavía contiene objetos, luego formatea al final. Si haces pipe a Format-Table, básicamente terminas el flujo de datos.
7) ¿Los one-liners son seguros para pegar en producción?
Los de solo lectura son generalmente seguros. Cualquier cosa que borre, pare servicios, reinicie o cambie configuración debe convertirse en un script con logging y modo dry-run. Si no puedes explicar su radio de impacto, no lo ejecutes.
8) ¿Cuál es la forma más rápida de detectar “este servidor es diferente” en un clúster?
Ejecuta el mismo comando en todos los nodos y ordena por la métrica que te importa (espacio libre, uptime, conteo de errores, valores de contadores). Los outliers son donde se esconde la verdad.
9) Mi comando es lento (como los cheques de tamaño de directorio). ¿Qué hago?
Usa las comprobaciones costosas solo cuando sean necesarias y delimítalas: rutas más pequeñas, menos objetivos recursivos o ejecútalas en horas no pico. Para monitoreo continuo instrumenta logs y cuotas en vez de volver a escanear el filesystem cada vez.
Próximos pasos prácticos
Haz esto mañana por la mañana:
- Elige cinco servidores que tocas semanalmente. Ejecuta el one-liner de flota para uptime y espacio libre. Encuentra el outlier y arréglalo.
- Añade una muestra de contadores de 2 minutos para cola de CPU, paginación y latencia de disco a tus notas estándar de incidentes. Deja de diagnosticar a partir de capturas de pantalla.
- Construye (o toma prestado) un pequeño script de “pulse check” con los comandos de arriba y ejecútalo diariamente. El objetivo no es la perfección; es notar la deriva antes de que sea una caída.
- Cuando necesites la GUI, úsala intencionalmente: para configuración profunda, no para descubrimiento impulsado por pánico.
Si quieres una prueba de toque para saber si tu práctica de ops está mejorando: mide con qué frecuencia puedes responder “¿qué cambió?” con evidencia en menos de cinco minutos. Los one-liners no son magia. Son palanca.