(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisboa

Cómo supervisar cambios en permisos NTFS con PowerShell: paso a paso

João Barros 18 de August de 2026 4 min de lectura

Este tutorial muestra cómo supervisar cambios en permisos NTFS con PowerShell para detectar cuándo las ACLs (Access Control Lists) de archivos o carpetas se modifican. Es útil para auditoría, seguridad y para mantener el control sobre quién tiene acceso a datos sensibles.

Requisitos previos

  • Windows 10/11 o Windows Server con PowerShell 5.1 o PowerShell 7+
  • Permisos de lectura en las carpetas a supervisar
  • Preferible ejecutar PowerShell con privilegios elevados para acceder a todas las ACLs
  • Editor de texto (ej.: Visual Studio Code) para guardar el script

Paso 1: Por qué supervisar ACLs y el enfoque

Los cambios en permisos NTFS no siempre generan un evento claro en el sistema. El enfoque aquí es leer periódicamente las ACLs de una carpeta/archivo, generar un hash representativo y comparar con la instantánea anterior. Cuando el hash cambia, se registra la diferencia y se envía una notificación sencilla.

Paso 2: Función para obtener una 'fingerprint' de la ACL

Vamos a crear una función que lea la ACL de una carpeta y cree una fingerprint consistente. Esto permite comparar versiones de forma rápida.

function Get-AclFingerprint {
    param(
        [Parameter(Mandatory)] [string] $Path
    )
    # Obtém a ACL e cria uma string ordenada para hashing
    $acl = Get-Acl -Path $Path
    $entries = $acl.Access | ForEach-Object {
        "{0}|{1}|{2}|{3}|{4}" -f $_.IdentityReference, $_.FileSystemRights, $_.AccessControlType, $_.InheritanceFlags, $_.PropagationFlags
    }
    $entries = $entries | Sort-Object
    $joined = $entries -join ";"
    # MD5 é suficiente para fingerprint (não para segurança criptográfica)
    $md5 = [System.Security.Cryptography.MD5]::Create()
    $bytes = [System.Text.Encoding]::UTF8.GetBytes($joined)
    $hash = $md5.ComputeHash($bytes)
    return ([System.BitConverter]::ToString($hash)).Replace("-","")
}

Paso 3: Capturar instantánea inicial y guardar en archivo

Guarde la fingerprint inicial en un archivo JSON para comparaciones futuras. Puede supervisar varias carpetas guardando un objeto por ruta.

$paths = @('C:\Dados\Projeto', 'C:\Logs')
$snapshot = @{}
foreach ($p in $paths) {
    if (Test-Path $p) {
        $snapshot[$p] = Get-AclFingerprint -Path $p
    }
}
$snapshot | ConvertTo-Json | Out-File -FilePath 'C:\MonitorACL\acl_snapshot.json' -Encoding UTF8

Paso 4: Script de supervisión y detección de cambios

Script que carga la instantánea, recalcula fingerprints y, al detectar un cambio, escribe en un log y guarda la nueva instantánea. También muestra cómo obtener la diferencia en las entradas ACL para contextualizar la modificación.

# Requer a função Get-AclFingerprint definida acima
$snapshotPath = 'C:\MonitorACL\acl_snapshot.json'
$logPath = 'C:\MonitorACL\acl_changes.log'
$paths = @('C:\Dados\Projeto', 'C:\Logs')

# Carrega snapshot existente
if (Test-Path $snapshotPath) {
    $oldSnapshot = Get-Content $snapshotPath -Raw | ConvertFrom-Json | ConvertTo-Hashtable
} else {
    $oldSnapshot = @{}
}

foreach ($p in $paths) {
    if (-not (Test-Path $p)) { continue }
    $newHash = Get-AclFingerprint -Path $p
    $oldHash = $oldSnapshot[$p]
    if ($oldHash -ne $null -and $newHash -ne $oldHash) {
        $time = (Get-Date).ToString('s')
        $msg = "[$time] ACL altered for $p (old:$oldHash new:$newHash)"
        $msg | Out-File -FilePath $logPath -Append -Encoding UTF8

        # Opcional: obter e registar entradas ACL actuais para análise
        $acl = Get-Acl -Path $p
        $entries = $acl.Access | ForEach-Object { "{0} {1} {2}" -f $_.IdentityReference, $_.FileSystemRights, $_.AccessControlType }
        ($time + ' - Entries:') | Out-File -FilePath $logPath -Append -Encoding UTF8
        $entries | Out-File -FilePath $logPath -Append -Encoding UTF8
    }
    # Actualiza snapshot em memória
    $oldSnapshot[$p] = $newHash
}

# Grava snapshot actualizado
$oldSnapshot | ConvertTo-Json | Out-File -FilePath $snapshotPath -Encoding UTF8

Paso 5: Programar ejecución periódica (ejemplo rápido)

Para supervisión continua, puede ejecutar el script en un bucle con retardo o usar el Task Scheduler. Ejemplo de bucle simple que se ejecuta cada 5 minutos (útil para pruebas).

while ($true) {
    & 'C:\MonitorACL\Check-AclChanges.ps1'
    Start-Sleep -Seconds 300
}

Comprobar el resultado

Abra el archivo de log definido (ej.: C:\MonitorACL\acl_changes.log) para ver entradas con marcas de tiempo cuando se produjeron cambios. Verifique también acl_snapshot.json para confirmar que los hashes se actualizaron. Si no aparece ningún registro a pesar de cambios, confirme permisos, rutas y si el script tiene acceso a Get-Acl para esos elementos.

Conclusión

Con este método sencillo puede supervisar cambios en permisos NTFS usando PowerShell, registrar eventos y guardar instantáneas para auditoría. Próximos pasos: integrar con el envío de e-mail o Teams cuando ocurra un cambio, y usar Event Forwarding para centralizar registros. Consejo: pruebe primero en carpetas no críticas para validar falsos positivos y ajustar la frecuencia de verificación.