lunes, 13 de abril de 2026

WINDOWS. LAPS. Check PCs


Propósito

A veces, viendo que en nuestro AD nuestros PCs tienen asignada una contraseña de LAPS creemos erróneamente que todo está funcionando bien. Hay que verificar alguna cosas más. que aquí explicaré, para tener más control
 
Vamos a planificar un script que no solo compruebe si un PC tiene contraseña de LAPS en el AD, sino que esta contraseña esté rotando cada 30 días como marca la GPO.

Pasos

La ejecución será sencilla, el resultado lo enviará por email.

 

Nos llegará un email con este formato:

 

No solo pone en el cuerpo del email los PCs encontrados, sino que los envía en un fichero adjunto para poder manipularlo. Es recomendable ejecutarlo entre 15 días y un mes, para ver si salen algún caso, tal como muestro en los pantallazos. Es evidente que si el PC no se enciende o no contacta con el AD, no se le puede cambiar la contraseña.

 

El código: 

<#
.DESCRIPCION
Script de auditoria LAPS en Active Directory.
Detecta equipos con LAPS activo cuya contrasena local no se ha rotado
en mas de 30 dias. El resultado se muestra en el cuerpo del email en
formato HTML  y se adjunta en CSV.

.DISENO
Entorno enterprise, solo lectura, sin impacto.
#>

Write-Host "=== AUDITORIA LAPS ===" -ForegroundColor Cyan

# ==========================
#  VARIABLES DEL USUARIO
# ==========================
$SMTPServer = "smtp.midominio.com"
$SMTPPort   = 25
$From       = "HD@midominio.com"
$To         = "Infra@midominio.com"
$Subject    = ""

# ==========================
#  RUTAS Y FECHAS
# ==========================
$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
$timestamp  = Get-Date -Format "yyyyMMdd_HHmm"
$csvFile    = "$scriptPath\LAPS_Auditoria_$timestamp.csv"

# ==========================
#  OBTENER EQUIPOS AD
# ==========================
$computers = Get-ADComputer -Filter * -Properties `
    msLAPS-PasswordExpirationTime,
    LastLogonDate,
    DistinguishedName,
    Enabled

$results = @()

foreach ($pc in $computers) {

    if (-not $pc."msLAPS-PasswordExpirationTime") { continue }

    $exp = [DateTime]::FromFileTimeUtc($pc."msLAPS-PasswordExpirationTime")
    $dias = (New-TimeSpan -Start $exp -End (Get-Date)).Days
    if ($dias -le 30) { continue }

    $ou = ($pc.DistinguishedName -split ",",2)[1]
    $estado = if ($pc.Enabled) { "Habilitado" } else { "Deshabilitado" }

    $results += [PSCustomObject]@{
        Equipo             = $pc.Name
        OU                 = $ou
        Equipo_Habilitado  = $estado
        LAPS_Activo        = "Si"
        Ultima_Rotacion    = $exp
        Dias_Sin_Cambiar   = $dias
        Ultima_Conexion    = $pc.LastLogonDate
    }
}

$resultsSorted = $results | Sort-Object Dias_Sin_Cambiar -Descending
$TotalEquipos = $resultsSorted.Count

# ==========================
#  EXPORTAR CSV
# ==========================
$resultsSorted | Export-Csv -Path $csvFile -NoTypeInformation -Encoding UTF8

# ==========================
#  GENERAR TABLA HTML
# ==========================
$HtmlRows = ""

foreach ($r in $resultsSorted) {

    $FechaRotacionHtml = if ($r.Ultima_Rotacion) {
        $r.Ultima_Rotacion.ToString("dd/MM/yyyy")
    } else {
        "N/D"
    }

    $FechaConexionHtml = if ($r.Ultima_Conexion) {
        $r.Ultima_Conexion.ToString("dd/MM/yyyy")
    } else {
        "Nunca"
    }

    $HtmlRows += "<tr>
        <td>$($r.Equipo)</td>
        <td>$($r.Equipo_Habilitado)</td>
        <td>$($r.Dias_Sin_Cambiar)</td>
        <td>$FechaRotacionHtml</td>
        <td>$FechaConexionHtml</td>
        <td>$($r.OU)</td>
    </tr>"
}

# ==========================
#  EMAIL HTML
# ==========================
$Subject = "$(Get-Date -Format 'yyyy-MM-dd - HHmm') - Listado equipos LAPS sin rotacion ($TotalEquipos)"

$Body = @"
<html>
<head>
<style>
body { font-family: Arial; font-size: 12px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #999; padding: 5px; }
th { background-color: #eeeeee; }
</style>
</head>
<body>

<h2>Auditoria LAPS Active Directory</h2>

<p>
Equipos con LAPS activo y mas de 30 dias sin cambio de contrasena local.
</p>

<ul>
<li>Total equipos listados: <b>$TotalEquipos</b></li>
<li>Fecha ejecucion: <b>$(Get-Date -Format "dd/MM/yyyy")</b></li>
</ul>

<table>
<tr>
<th>Equipo</th>
<th>Estado</th>
<th>Dias sin cambiar</th>
<th>Ultima rotacion</th>
<th>Ultima conexion</th>
<th>OU</th>
</tr>
$HtmlRows
</table>

<p>
Se adjunta el fichero CSV con el detalle completo.
</p>

</body>
</html>
"@

Send-MailMessage `
    -From $From `
    -To $To `
    -Subject $Subject `
    -Body $Body `
    -BodyAsHtml `
    -SmtpServer $SMTPServer `
    -Port $SMTPPort `
    -Attachments $csvFile

Write-Host "Email enviado correctamente" -ForegroundColor Green
Write-Host "=== FIN DE AUDITORIA ===" -ForegroundColor Cyan 
 
 
by GoN | Published: April 2026 | Last Updated:
 

No hay comentarios: