Cómo supervisar cambios en permisos NTFS con PowerShell: paso a paso
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.