Cómo crear un snapshot de archivos en PowerShell: paso a paso
Este tutorial muestra cómo crear un snapshot de archivos en PowerShell para registrar el estado de una carpeta, detectar cambios y facilitar reversiones. Es una técnica simple y eficaz para auditoría, detección de cambios no deseados y backups incrementales en entornos donde no existe un sistema de versionado más avanzado. En entornos reales, un snapshot por día puede ser suficiente; en entornos sensibles, puedes ejecutar este proceso cada hora. Los ejemplos concretos abajo muestran cómo generar, comparar y automatizar snapshots.
Requisitos previos
- Windows con PowerShell 5.1 o PowerShell 7+
- Permisos de lectura/escritura en la carpeta objetivo (al menos lectura para todos los archivos a monitorizar, escritura si vas a guardar snapshots)
- Conocimientos básicos de PowerShell (cmdlets como Get-ChildItem, Get-FileHash, Export-Csv)
Nota sobre rendimiento: calcular hashes de archivos grandes depende de I/O y CPU. Por ejemplo, en disco SSD una máquina moderna puede calcular SHA256 a ~100 MB/s; 10 GB de archivos pueden tardar ~100 segundos en lectura pura. Prueba en una carpeta pequeña (100–1000 archivos) antes de escalar a 50k archivos.
Paso 1: Elegir la carpeta y el formato del snapshot
Decide qué carpeta vas a monitorizar y el formato del snapshot. Aquí usamos un CSV simple con campos: RelativePath, FullPath, Length, LastWriteTime y Hash (SHA256). El CSV es portátil y fácil de comparar con Import-Csv o Excel. Guardar la marca de fecha/hora en formato ISO 8601 ('o') facilita ordenación y parsing automático.
Ejemplo de dimensionamiento: un snapshot de 10k archivos (5 campos) tiende a quedarse entre 1–5 MB dependiendo de la longitud de las rutas. Si necesitas compresión, guarda los CSV en .zip o usa gzip forzado por otras herramientas.
Paso 2: Script básico para generar el snapshot
Crea un script que recorra la carpeta de forma recursiva, calcule el hash de cada archivo y escriba un CSV. El hash detecta cambios de contenido incluso si la marca de tiempo no cambia. Usa SHA256 en lugar de SHA1, que hoy en día es menos recomendable.
# GerarSnapshot.ps1
param(
[string]$Folder = ".",
[string]$SnapshotPath = "snapshot.csv"
)
$base = (Resolve-Path $Folder).Path
Get-ChildItem -Path $base -File -Recurse | ForEach-Object {
$rel = $_.FullName.Substring($base.Length).TrimStart('\\')
$hash = Get-FileHash -Path $_.FullName -Algorithm SHA256
[PSCustomObject]@{
RelativePath = $rel
FullPath = $_.FullName
Length = $_.Length
LastWriteTime = $_.LastWriteTime.ToString('o')
Hash = $hash.Hash
}
} | Export-Csv -Path $SnapshotPath -NoTypeInformation -Encoding UTF8
Guárdalo como GerarSnapshot.ps1. Ejecuta: .\GerarSnapshot.ps1 -Folder C:\\Dados -SnapshotPath C:\\snapshots\\snap1.csv. En un ejemplo práctico, un conjunto de 2 000 archivos (total 2 GB) puede tardar 1–3 minutos en generar el snapshot dependiendo del disco.
Paso 3: Comparar dos snapshots
Para detectar archivos añadidos, eliminados o modificados, carga dos CSV y haz una comparación por RelativePath y Hash. El método abajo usa Compare-Object para cambios en la lista de rutas y una comparación adicional para cambios de contenido (hash diferente).
# CompararSnapshots.ps1
param(
[string]$OldSnapshot,
[string]$NewSnapshot
)
$old = Import-Csv -Path $OldSnapshot | Sort-Object RelativePath
$new = Import-Csv -Path $NewSnapshot | Sort-Object RelativePath
# Archivos nuevos
$added = Compare-Object -ReferenceObject $old -DifferenceObject $new -Property RelativePath -PassThru | Where-Object {$_.PSObject.Properties['SideIndicator'].Value -eq '=>'}
# Archivos eliminados
$removed = Compare-Object -ReferenceObject $old -DifferenceObject $new -Property RelativePath -PassThru | Where-Object {$_.PSObject.Properties['SideIndicator'].Value -eq '<='}
# Archivos con la misma ruta pero hash diferente -> modificados
$joined = @()
foreach ($n in $new) {
$o = $old | Where-Object { $_.RelativePath -eq $n.RelativePath }
if ($o) {
if ($o.Hash -ne $n.Hash) {
$joined += [PSCustomObject]@{RelativePath=$n.RelativePath; OldHash=$o.Hash; NewHash=$n.Hash}
}
}
}
# Resultado simple
[PSCustomObject]@{
Added = $added.Count
Removed = $removed.Count
Modified = $joined.Count
}
# Lista detallada (opcional)
if ($added) { Write-Output "--- Added ---"; $added | Select-Object RelativePath }
if ($removed) { Write-Output "--- Removed ---"; $removed | Select-Object RelativePath }
if ($joined) { Write-Output "--- Modified ---"; $joined }
Ejecuta: .\CompararSnapshots.ps1 -OldSnapshot C:\\snapshots\\snap1.csv -NewSnapshot C:\\snapshots\\snap2.csv. Un resultado típico puede ser: Added = 5, Removed = 2, Modified = 10. Revisa las listas detalladas para confirmar los cambios.
Paso 4: Ignorar archivos que cambian con frecuencia
Algunas carpetas tienen archivos temporales (logs, caches) que solo generan ruido. Filtra por extensión, patrón o tamaño antes de calcular el hash para reducir tiempo y ruido. Por ejemplo, evita *.log, *.tmp y archivos de menos de 1 KB.
# Ejemplo de filtro en GerarSnapshot.ps1
$exclude = '*.log','*.tmp'
Get-ChildItem -Path $base -File -Recurse | Where-Object {
$match = $false
foreach ($pat in $exclude) { if ($_.Name -like $pat) { $match = $true; break } }
-not $match -and $_.Length -gt 1024
} | ForEach-Object { ... }
Este enfoque reduce significativamente el tiempo: al excluir el 30% de los archivos temporales, la generación del snapshot puede pasar de 10 minutos a 7 minutos en un ejemplo con muchas pequeñas modificaciones.
Paso 5: Automatizar y preservar historiales
Puedes ejecutar el script regularmente con el Task Scheduler (p. ej.: diariamente o cada hora) y guardar snapshots con timestamp en el nombre. Mantén solo los N últimos para no llenar el disco; 7 es un buen valor para retención semanal.
# Ejemplo para guardar con timestamp
$ts = (Get-Date).ToString('yyyyMMddHHmmss')
.\GerarSnapshot.ps1 -Folder C:\\Dados -SnapshotPath C:\\snapshots\\snapshot_$ts.csv
# Eliminar snapshots antiguos, queda solo los 7 más recientes
Get-ChildItem C:\\snapshots -Filter 'snapshot_*.csv' | Sort-Object LastWriteTime -Descending | Select-Object -Skip 7 | Remove-Item
Programación práctica: crea una Task que ejecute el script a las 02:00 o en horarios de baja utilización. Si la carpeta tiene muchos archivos, define una alerta por email en caso de fallo (p. ej.: integración con Send-MailMessage o sistemas de monitorización).
Verificar el resultado
Confirma que los CSV se han generado y que la comparación muestra números coherentes. Abre los CSV en Excel o usa Import-Csv para inspeccionar. Haz una verificación manual en algunos archivos listados en Added/Removed/Modified: por ejemplo, usa Get-FileHash en el archivo específico para confirmar el hash actual. Si estás probando, crea cambios artificiales (editar un archivo de 1 KB) para ver el comportamiento.
Conclusión
Has aprendido a crear y comparar snapshots de archivos en PowerShell, útil para auditoría y backups incrementales simples. Próximos pasos posibles: integrar notificaciones por email, sincronizar snapshots a OneDrive/SharePoint o almacenar solo metadatos en un sistema central. Consejo práctico: empieza probando en una carpeta pequeña (100–1 000 archivos) para validar filtros y rendimiento. ¿Qué carpeta quieres monitorizar primero?