miércoles, 21 de enero de 2026

WINDOWS. Security. LAPS

 


    Propósito

    El objetivo este post es explicar un poco como implantar una configuración de Microsoft LAPS.
    Microsoft LAPS (Local Administrator Password Solution) es una herramienta de Microsoft diseñada para gestionar automáticamente las contraseñas de las cuentas de administrador local en equipos Windows dentro de un dominio.
    Esto solo son algunas de las muchas opciones que hay para gestionar una implantación de este tipo.
    Usa la información oficial de Microsoft para hacer este proceso. Este post úsalo de apoyo y consulta por si tienes alguna duda o problema.
    Antes de ponerlo en un entorno de producción valídalo en un entorno de pruebas.
    Aplicar una configuración de LAPS sin conocimiento y todas las garantías de éxito podría tener un impacto en las infraestructuras.
    Revisa el documento completo antes de empezar y su puedes contrástalo con Microsoft por si han habido cambios.
    Pasos

    Para que funcione LAPS hay que tener en cuenta varios fases

    [01] Preparar el AD
    [02] Asignar configurar las OU
    [03] Script para consultar la OU autorizadas por LAPS
    [04] Check cuantos computers han entrado en LAPS
    [05] Laps Diagnosticos
    [06] Como comprobar si un PC tiene LAPS
    [07] GPO
    [08] Notas

[01] Preparar el AD

Debemos tener la plantilla preparada para la gestión del LAPS:

Copy from:

C:\Windows\PolicyDefinitions\LAPS.admx

C:\Windows\PolicyDefinitions\<language>\LAPS.adml

 

Copy to:

\\<domain>\SYSVOL\<domain>\Policies\PolicyDefinitions\

\\<domain>\SYSVOL\<domain>\Policies\PolicyDefinitions\<language>\

Verifica que el esquema de AD tiene los atributos del nuevo LAPS

Ejecuta en tu DC:

COMANDO: Get-ADObject -SearchBase "CN=Schema,CN=Configuration,DC=Midomino,DC=com" -LDAPFilter "(lDAPDisplayName=msLAPS-EncryptedPassword)"


COMANDO: Get-ADObject -SearchBase (Get-ADRootDSE).schemaNamingContext -LDAPFilter "(|(name=*laps*)(name=*admPwd*))" | Select-Object name

Si no lo tiene hay que prepararlo 

Es recomendable que el usuario que lo vaya a configurar pertenezca a los grupos:

·         Scheme Administrator /      Organization Administrator       

     Para que la configuración no de problemas se debe hacer desde un Controlador de Dominio que tenga el módulo de LAPS instalado.

ç     Empezamos. NO debes ejecutarlo si:

  • El esquema ya fue actualizado previamente (solo se hace una vez por bosque).

  • Tu dominio ya tiene los atributos de LAPS nuevo (Windows Server 2019/2022 + actualizaciones ya los incluyen).

  • Estás usando LAPS Legacy (el antiguo) y no piensas migrar.

     Esta configuración podría cambiar en función a la evolución que de Microsoft a este servicio. Mucho cuidado en configurar el LAPS sin haber tenido en cuenta los puntos anteriores.

      Preparamos el AD

       C:\> Update-LapsADSchema


Debemos crear 2 nuevos grupos de usuarios, uno que solo podrá leer las contraseñas y otro para gestionar el LAPS

[] Permiso de lectura

COMMAND: PS C:\> Set-LapsADReadPasswordPermission -Identity "OU=LAPS,DC=midominio,DC=com" -AllowedPrincipals @("laps\LapsPasswordReadersGroup")

[] Permitir acceso a contraseñas cifradas (Password Encryption Allowed Principals)

Para visualizar contraseñas cuando LAPS está configurado con cifrado, los usuarios deben pertenecer a un grupo autorizado.

COMMAND: Set-LapsADPasswordEncryptionAllowedPrincipals -Identity "OU=LAPS,DC=midominio,DC=com" -AllowedPrincipals "Domain Admins","Grupo_Laps_Management"

Members of the Domain Admins group already have password query permission by default.

[] Consultar permisos extendidos (Query Extended Rights Permissions)

Este comando permite verificar qué grupos o usuarios tienen permisos avanzados sobre la OU, incluyendo lectura de contraseñas y escritura de atributos gestionados por LAPS.

COMMAND: Find-LapsADExtendedRights -Identity "OU=LAPS,DC=midominio,DC=com"


Command: PS C:\> Import-Module LAPS


Hay que autorizar a un grupo del AD de usuarios para poder leer las contraseñas del LAPS


[02] Asignar configurar las OU

Este será el día a día cuando debamos modificarlo

En cada OU que queramos que se le aplique la GPO hay que autorizarla por comandos


Grupo con permisos de LAPS: GG_Laps_Management_PCs


# VERIFICAR PERMISOS
Find-LapsADExtendedRights -Identity "OU=Standard,OU=Computers,OU=Tier2,DC=MiDominio,DC=com"



#Asigna LAPS A UNA OU. Permitir que los equipos escriban su contraseña
Set-LapsADComputerSelfPermission -Identity "OU=Standard,OU=Computers,OU=Tier2,DC=MiDominio,DC=com"

Aquí aplico permisos de dos maneras, solo funcionará una en función como tengas configurado el LAPS (antiguo o moderno)

#LAPS OLD
Set-LapsADReadPasswordPermission -Identity "OU=Standard,OU=Computers,OU=Tier2,DC=MiDominio,DC=com" -AllowedPrincipals "MiDominio\GG_Laps_Management_PCs"



# LAPS NEW - CIFRADAS
Set-LapsADPasswordEncryptionAllowedPrincipals -Identity "OU=Standard,OU=Computers,OU=Tier2,DC=MiDominio,DC=com" -AllowedPrincipals "MiDominio\GG_Laps_Management_PCs"

# VERIFICAR PERMISOS
Find-LapsADExtendedRights -Identity "OU=Standard,OU=Computers,OU=Tier2,DC=MiDominio,DC=com"


Apunte, solo aplicas permisos en OU=Standard, entonces:
  • Sub1 NO tiene permisos LAPS
  • Sub2 NO tiene permisos LAPS
  • Sub3 NO tiene permisos LAPS
A menos que ejecutes los comandos también en ellas.

[03] Script para consultar la OU autorizadas por LAPS

Se recorre el AD y mira todas las OU, saca las que con el comando anterior han sido autorizadas

Import-Module ActiveDirectory

 

# GUID del atributo específico

$lapsEncryptedGuid = [guid]"f3531ec6-6330-4f8e-8d39-7a671fbac605"

 

# Obtener todas las OUs del dominio

$OUs = Get-ADOrganizationalUnit -Filter *

 

$ousWithWritePermission = foreach ($OU in $OUs) {

    # Leer ACL de la OU usando ADSI

    $entry = [ADSI]"LDAP://$($OU.DistinguishedName)"

    $acl = $entry.ObjectSecurity

 

    # Filtrar ACEs con WriteProperty sobre el GUID específico

    $writeAce = $acl.Access | Where-Object {

        ($_.ActiveDirectoryRights -band [System.DirectoryServices.ActiveDirectoryRights]::WriteProperty) -and

        $_.ObjectType -eq $lapsEncryptedGuid

    }

 

    if ($writeAce) {

        foreach ($ace in $writeAce) {

            [PSCustomObject]@{

                OU        = $OU.DistinguishedName

                Trustee   = $ace.IdentityReference

                Inherited = $ace.IsInherited

            }

        }

    }

}

 

# Mostrar lista única de OUs con permisos WRITE

if ($ousWithWritePermission) {

    $ousWithWritePermission |

        Sort-Object OU -Unique |

        Format-Table -AutoSize

} else {

    Write-Output "No se encontraron OUs con permisos WRITE sobre ms-LAPS-Encrypted-Password-Attributes."

}





Otra opcion

Comando: Get-ADObject -SearchBase (Get-ADRootDSE).schemaNamingContext -LDAPFilter "(name=*LAPS*)"




[04] Check cuantos computers han entrado en LAPS

Se verifica los PCs que tiene algo dentro de la contraseña de LAPS

 Write-Host "Ejecutando v3.1..."

Write-Host "Hay que asegurarse que las OUs donde hay equipos LAPS este autorizadas con: Set-LapsADComputerSelfPermission y que recorre todas las Sub-OUS, este proceso puede durar varios minutos. "

# --- Configuración ---

$ou = "OU=Equipos,DC=midominio,DC=com"

# Fecha y hora para el nombre del archivo

$timestamp = Get-Date -Format "yyyyMMdd_HHmm"

$csvPath = "C:\scripts\Computer_LAPS_with_assigned_passwd_$timestamp.csv"

 # --- Obtener equipos de la OU ---

$computers = Get-ADComputer -SearchBase $ou -Filter * -Properties Description, MemberOf, DistinguishedName

 # --- Lista de resultados ---

$resultados = @()

 foreach ($computer in $computers) {

    try {

        # Intenta obtener la contraseña con el nuevo esquema de LAPS

        $laps = Get-LapsADPassword -Identity $computer.Name -ErrorAction Stop

         if ($laps) {

            # Obtener OU desde el DN

            $computerOU = ($computer.DistinguishedName -split ",",2)[1]

             # Obtener grupos del AD

            $groups = $computer.MemberOf | ForEach-Object {

                ($_ -split ",")[0] -replace "^CN="

            }

             $resultados += [PSCustomObject]@{

                ComputerName = $computer.Name

                Description  = $computer.Description

                OU           = $computerOU

                ADGroups     = ($groups -join ";")

                PasswordSet  = $true

                Expiration   = $laps.ExpirationTimestamp

            }

        }

    }

    catch {

        # No se añade a la lista

    }

}

 # --- Exportar a CSV ---

$resultados | Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8

 Write-Host "Archivo CSV generado correctamente: $csvPath"

Write-Host "Total de filas exportadas: $($resultados.Count)"

 





[05] Laps Diagnosticos

COMANDO: Get-LapsDiagnostics

Get-LapsDiagnostics: all data for this run was written to the following zip file:

 C:\Users\R\AppData\Local\Temp\LapsDiagnostics\LapsDiagnostics_DC_2025122312_155158.zip



[06] Como comprobar si un PC tiene LAPS

COMANDO: Get-ADComputer PC001 -Properties msLAPS-PasswordExpirationTime, msLAPS-EncryptedPassword


Si esos atributos tienen valores, LAPS está aplicado y funcionando.

Si aparecen vacíos o null, el equipo no ha aplicado la GPO o no ha podido escribir en AD.


[07] GPO











[08] Script interesante 


Detecta TODAS las OUs donde LAPS está realmente aplicado
Comprueba permisos LAPS (lectura, cifrado, self‑permission)
Detecta inconsistencias
Genera un informe claro en pantalla

Write-Host "=== AUDITORIA LAPS EN OUs CON EQUIPOS ===" -ForegroundColor Cyan

# Ruta del script para guardar el CSV en la misma carpeta
$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path

# Fecha y hora para el archivo
$timestamp = (Get-Date).ToString("yyyyMMdd_HHmm")

# Detectar atributos disponibles en el esquema
$schema = (Get-ADObject -SearchBase (Get-ADRootDSE).schemaNamingContext -LDAPFilter "(objectClass=attributeSchema)" -Properties lDAPDisplayName).lDAPDisplayName

$hasNewLAPS = $schema -contains "msLAPS-PasswordExpirationTime"
$hasLegacyLAPS = $schema -contains "ms-Mcs-AdmPwdExpirationTime"

Write-Host "Atributos detectados:" -ForegroundColor Yellow
Write-Host " - Windows LAPS: $hasNewLAPS"
Write-Host " - LAPS Legacy: $hasLegacyLAPS"
Write-Host ""

# Construir lista de propiedades validas
$props = @()
if ($hasNewLAPS) { $props += "msLAPS-PasswordExpirationTime" }
if ($hasLegacyLAPS) { $props += "ms-Mcs-AdmPwdExpirationTime" }

# Obtener todas las OUs
$OUs = Get-ADOrganizationalUnit -Filter *

$results = @()
$OUsSinPermisos = @()
$OUsPeligrosas = @()

foreach ($ou in $OUs) {

    $ouDN = $ou.DistinguishedName

    # Obtener equipos de la OU
    try {
        $computers = Get-ADComputer -Filter * -SearchBase $ouDN -Properties $props -ErrorAction Stop
    }
    catch {
        continue
    }

    # Saltar OUs sin equipos
    if ($computers.Count -eq 0) { continue }

    # 1. Intentar obtener permisos LAPS sin romper el script
    try {
        $rights = Find-LapsADExtendedRights -Identity $ouDN -ErrorAction Stop
    }
    catch {
        $rights = $null
    }

    # 2. Detectar si hay equipos con atributos LAPS
    $lapsActive = $false
    foreach ($c in $computers) {
        foreach ($p in $props) {
            if ($c.$p) { $lapsActive = $true; break }
        }
        if ($lapsActive) { break }
    }

    # 3. SELF permission
    $selfPermission = $false
    if ($rights) {
        if ($rights.ExtendedRightHolders -match "SELF") { $selfPermission = $true }
    }

    # 4. Detectar automaticamente todos los grupos con permisos LAPS
    $gruposLAPS = @()
    if ($rights) {
        foreach ($g in $rights.ExtendedRightHolders) {
            if ($g -notmatch "SELF") {
                $gruposLAPS += $g
            }
        }
    }

    # Registrar OUs sin permisos correctos
    if (-not $selfPermission -or $gruposLAPS.Count -eq 0) {
        $OUsSinPermisos += $ouDN
    }

    # Registrar OUs con demasiados grupos (riesgo)
    if ($gruposLAPS.Count -gt 3) {
        $OUsPeligrosas += $ouDN
    }

    # Resultado
    $results += [PSCustomObject]@{
        OU = $ouDN
        PermisosLAPS = if ($rights) { "Si" } else { "No" }
        SELF = if ($selfPermission) { "Si" } else { "No" }
        GruposConPermisos = if ($gruposLAPS.Count -gt 0) { ($gruposLAPS -join "; ") } else { "Ninguno" }
        EquiposConLAPS = if ($lapsActive) { "Si" } else { "No" }
        NumeroEquipos = $computers.Count
    }
}

# Mostrar tabla
$results | Sort-Object OU | Format-Table -AutoSize

# Exportar CSV en la misma carpeta del script
$exportPath = "$scriptPath\LAPS_Auditoria_$timestamp.csv"
$results | Sort-Object OU | Export-Csv $exportPath -NoTypeInformation -Encoding UTF8

Write-Host "`nCSV exportado en: $exportPath" -ForegroundColor Green

# Mostrar recomendaciones al final
Write-Host ""
Write-Host "=== RECOMENDACIONES ===" -ForegroundColor Cyan

Write-Host "`n1) OUs sin permisos LAPS correctos:" -ForegroundColor Yellow
if ($OUsSinPermisos.Count -eq 0) {
    Write-Host " - Todas las OUs estan correctamente configuradas."
} else {
    $OUsSinPermisos | ForEach-Object { Write-Host " - $_" }
}

Write-Host "`n2) Como aplicar permisos LAPS a todas las OUs con PCs:" -ForegroundColor Yellow
Write-Host "   Set-LapsADComputerSelfPermission -Identity <OU>"
Write-Host "   Set-LapsADReadPasswordPermission -Identity <OU> -AllowedPrincipals <GrupoLectura>"
Write-Host "   Set-LapsADPasswordEncryptionAllowedPrincipals -Identity <OU> -AllowedPrincipals <GrupoLectura>"

Write-Host "`n3) OUs con permisos peligrosos (demasiados grupos con acceso):" -ForegroundColor Yellow
if ($OUsPeligrosas.Count -eq 0) {
    Write-Host " - No se han detectado OUs con exceso de grupos."
} else {
    $OUsPeligrosas | ForEach-Object { Write-Host " - $_" }
}

Write-Host "`n=== FIN DE AUDITORIA ===" -ForegroundColor Cyan




[09] Notas

Para acceder a las estaciones de trabajo con LAPS, solo los administradores locales deben tener acceso. Los administradores de dominio lo deben tener prohibido. 

No debería haber un usuario con contraseña común en más de un PC.

Sería recomendable renombrar por GPO el administrador local.

Sería recomendable, hacer una exportación cada 15 días de las contraseñas, en un lugar seguro, con contraseña y cifrado. Por si hay algún problema poder consultarla.

Solo los usuarios que den soporte deberían poder consultar la contraseña, siempre elevándose con un usuario privilegiado especial.

Se debería auditar todos los accesos que consulten las contraseñas de LAPS.

Pendiente un Script semanal comprobando si hay algún Host en el dominio que aún no se le aplique el LAPS que se ejecute al menos una vez a la semana.


by GoN | Published: Jan 2026 | Last Updated Mar 2026:

No hay comentarios: