Get-LocalUser: auditar cuentas locales en Windows con PowerShell

Get-LocalUser: auditar cuentas locales en Windows con PowerShell

¿Sabes exactamente cuántas cuentas de usuario existen en tu Windows en este momento? Mucha gente no lo sabe — y esa es justamente la brecha que un atacante con acceso inicial va a explotar: crear una cuenta oculta con nombre genérico, habilitarla con contraseña y mantener persistencia silenciosa. Get-LocalUser es el cmdlet que expone todo esto en una sola línea.

Qué es Get-LocalUser

El Get-LocalUser forma parte del módulo Microsoft.PowerShell.LocalAccounts, disponible de forma nativa desde PowerShell 5.1 (Windows 10 / Server 2016 en adelante). Devuelve todos los usuarios locales de la máquina — cuentas creadas manualmente, cuentas integradas del sistema (Administrator, Guest, DefaultAccount, WDAGUtilityAccount) y cuentas vinculadas a una cuenta Microsoft.

A diferencia de net user, Get-LocalUser devuelve objetos estructurados que puedes filtrar, comparar y exportar con facilidad.

Listando todas las cuentas locales

Abre PowerShell como administrador y ejecuta:

Get-LocalUser

La salida incluye las columnas más importantes para una auditoría inmediata:

Name               Enabled Description
----               ------- -----------
Administrador      False   Cuenta interna para administrar el equipo
DefaultAccount     False   Cuenta de usuario gestionada por el sistema
Guest              False   Cuenta interna para acceso de invitado
juan               True
WDAGUtilityAccount False   Cuenta usada por Windows Defender...

Cualquier cuenta con Enabled: True y nombre no reconocido — o el propio Guest habilitado — merece investigación.

Filtrando por estado y propiedades

El cmdlet acepta filtro por nombre, o puedes usar Where-Object para condiciones más específicas:

# Solo cuentas habilitadas
Get-LocalUser | Where-Object { $_.Enabled -eq $true }

# Cuentas sin fecha de expiración (riesgo: sin ciclo de vida definido)
Get-LocalUser | Where-Object { $_.AccountExpires -eq $null -and $_.Enabled -eq $true }

# Cuentas que nunca iniciaron sesión
Get-LocalUser | Where-Object { $_.LastLogon -eq $null }

Las cuentas habilitadas sin expiración y sin historial de inicio de sesión son una señal clara de una cuenta creada para persistencia o de una cuenta olvidada — ambas deberían desactivarse o eliminarse.

Verificando miembros de grupos locales

¿Quién está en el grupo Administradores?

Cualquier cuenta no autorizada en el grupo Administradores es un compromiso en curso — no una sospecha, una certeza.

Get-LocalGroupMember -Group "Administradores"

En inglés (Administrators), dependiendo de la versión de Windows:

Get-LocalGroupMember -Group "Administrators"

La salida muestra nombre, tipo (User/Group) y SID (Security Identifier). Compara el SID con el esperado cuando encuentres nombres desconocidos — a veces los atacantes crean cuentas con nombres similares a las existentes (admn en lugar de admin).

# Listar todos los grupos locales y sus miembros
Get-LocalGroup | ForEach-Object {
    $group = $_.Name
    Get-LocalGroupMember -Group $group | Select-Object @{n="Grupo";e={$group}}, Name, ObjectClass
}

Detalles completos de una cuenta específica

Get-LocalUser -Name "juan" | Select-Object *

Esto expone propiedades que no aparecen en el listado estándar:

  • PasswordLastSet — cuándo se cambió la contraseña por última vez
  • PasswordExpires — si la contraseña expira (las cuentas de servicio suelen tener esto deshabilitado)
  • UserMayChangePassword — si el usuario puede cambiar su propia contraseña
  • AccountExpires — fecha de expiración de la cuenta
  • LastLogon — fecha del último inicio de sesión exitoso

Exportando a CSV: informe de auditoría completo

Para documentación o análisis posterior, exporta todo de una vez:

Get-LocalUser | Select-Object Name, Enabled, LastLogon, PasswordLastSet, AccountExpires, Description |
    Export-Csv -Path "$env:USERPROFILE\Desktop\auditoria-cuentas-$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation -Encoding UTF8

El archivo generado en el escritorio incluye la fecha en el nombre — útil para comparar capturas semanales e identificar cuentas nuevas entre un periodo y otro.

¿Cómo identificar cuentas creadas recientemente?

Get-LocalUser no expone directamente la fecha de creación de la cuenta, pero puedes cruzarlo con el registro de eventos de seguridad. El evento 4720 registra la creación de cuentas locales:

Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4720} |
    Select-Object TimeCreated, Message | Format-List

Combinado con Get-WinEvent para investigar eventos en Windows, puedes rastrear exactamente cuándo se creó cada cuenta y por qué proceso — un dato esencial en la respuesta a incidentes.

Desactivar o eliminar una cuenta sospechosa

¿Encontraste algo raro? Desactívala antes de investigar (es menos destructivo que eliminarla):

# Desactivar
Disable-LocalUser -Name "cuenta-sospechosa"

# Eliminar (irreversible)
Remove-LocalUser -Name "cuenta-sospechosa"

Desactivar preserva el SID y el historial para análisis forense; eliminar borra el rastro. En un escenario de respuesta a incidentes, desactiva siempre primero.

Verificación rápida de cuentas integradas problemáticas

Tres verificaciones que todo sysadmin debería ejecutar en cualquier máquina nueva:

# ¿Guest habilitado? (nunca debería estarlo)
Get-LocalUser -Name "Guest" | Select-Object Name, Enabled

# ¿La cuenta Administrator integrada está activa?
Get-LocalUser -Name "Administrator" | Select-Object Name, Enabled, LastLogon

# Cuentas con la contraseña configurada para no expirar nunca
Get-LocalUser | Where-Object { $_.PasswordExpires -eq $null -and $_.Enabled -eq $true } |
    Select-Object Name, PasswordLastSet

Guest habilitado, la cuenta Administrator integrada activa sin motivo aparente y cuentas con contraseña permanente son hallazgos clásicos en auditorías de hardening. Para la lista completa de configuraciones que refuerzan Windows, revisa el post sobre Windows 11 más seguro: 10 configuraciones para activar hoy.

Get-LocalUser en red: auditando varias máquinas

El cmdlet no tiene parámetro -ComputerName (a diferencia de cmdlets más antiguos), pero funciona vía PowerShell Remoting:

$equipos = @("PC-01", "PC-02", "PC-03")

$resultado = Invoke-Command -ComputerName $equipos -ScriptBlock {
    Get-LocalUser | Where-Object { $_.Enabled -eq $true } |
        Select-Object Name, Enabled, LastLogon, @{n="Equipo";e={$env:COMPUTERNAME}}
}

$resultado | Export-Csv -Path "auditoria-red.csv" -NoTypeInformation -Encoding UTF8

Esto genera un inventario consolidado de todas las cuentas habilitadas en varias estaciones — el punto de partida de cualquier auditoría de identidades en un entorno corporativo.

Para monitorear conexiones de red sospechosas en esas mismas máquinas, complementa con Get-NetTCPConnection para monitorear puertos abiertos en Windows. Y si necesitas revisar los registros de autenticación cruzándolos con eventos de seguridad, la guía de auditoría de registros de seguridad con PowerShell cubre ese flujo completo.

Auditar cuentas locales no es una tarea de una sola vez — debería ser rutina mensual en cualquier entorno. Una cuenta huérfana o creada por malware puede pasar desapercibida durante meses si nadie la verifica. Get-LocalUser tarda menos de un minuto en ejecutarse y puede mostrar exactamente lo que está esperando a ser encontrado.

Comentarios