Copias de seguridad automáticas en Windows con Robocopy (y PowerShell): simples, rápidas y fiables

Un script híbrido (Batch + PowerShell) que hace copia completa, comprime en ZIP por fecha, elimina backups antiguos, registra todo y calcula tiempos. Ideal para pymes, autónomos y despachos que quieren protección local sin montar infra compleja.

¿Por qué Robocopy?

  • Viene en Windows, es muy fiable, entiende NTFS (atributos, permisos) y tiene modos resilientes para enlaces, reintentos, etc.
  • Es perfecto para copias diarias a disco local/externo/NAS sin quebraderos de cabeza.
  • Con un poco de PowerShell, añadimos ZIP, limpieza por retención, hash opcional y logs legibles.

Qué hace este flujo

  1. Copia completa desde origen a carpeta de trabajo del día (timestamp) usando Robocopy.
  2. Comprime la copia del día en un .zip (uno por día).
  3. Limpieza de backups antiguos (tanto carpetas como ZIP) según retención configurable.
  4. Logs detallados (+ evento en el Visor de sucesos si quieres).
  5. Cálculo de duración y código de salida claro para integrarlo con monitorización.
  6. Ejecución manual o automática con el Programador de tareas.

Mejores prácticas aplicadas

  • Rendimiento: /MT:16 (multihilo), /R:3 /W:5 (reintentos moderados), /Z (reinicia transferencias), /FFT (tolerancia timestamps FAT/NAS), /COPY:DAT (datos, atributos y timestamps).
  • Calidad de datos: /DCOPY:T para directorios, /XJ para evitar bucles con junctions típicas de perfiles.
  • Control y seguridad: exclusiones (/XD, /XF), logs separados diarios, y opción de hash (SHA256) para validar que el ZIP no se corrompió.
  • Rotación simple por días, evitando “crecimiento infinito”.

Nota: si necesitas copiar archivos bloqueados (bases de datos, PST abiertos, etc.), plantéate usar VSS (instantánea) y copiar desde el snapshot. Podemos derivarlo a un .dsh con diskshadow o a wbadmin. Para la mayoría de oficinas y documentos ofimáticos, la ventana fuera de horario + Robocopy suele bastar.


Script híbrido mejorado

  • Configuración al principio (rutas y retención).
  • Registro en logFolder\backup-YYYYMMDD.log.
  • ZIP en zipFolder\Backup-YYYYMMDD.zip.
  • Limpieza de ficheros/carpetas con más de diasRetencion.

Copia, pega y ajusta rutas. Guarda como robocopy_backups.bat.

@echo off
setlocal enableextensions enabledelayedexpansion

REM ======== CONFIGURACION ========
set "origen=C:\Datos"
set "baseDestino=D:\Backups\Diario"
set "zipFolder=D:\Backups\Zip"
set "logFolder=D:\Backups\Logs"
set "diasRetencion=14"

REM (Opcional) Exclusiones: carpetas y archivos
set "EXCL_DIRS=System Volume Information $Recycle.Bin node_modules .git .cache"
set "EXCL_FILES=Thumbs.db *.tmp *.log~"

REM (Opcional) Hash del ZIP (1=si, 0=no)
set "GENERAR_HASH=1"

REM ======== PREPARACION ========
for /f "tokens=1-3 delims=/-. " %%a in ('wmic os get localdatetime ^| find "."') do set "YYYYMMDD=%%a" & set "HHMMSS=%%b"
set "YYYY=%YYYYMMDD:~0,4%"
set "MM=%YYYYMMDD:~4,2%"
set "DD=%YYYYMMDD:~6,2%"
set "HOY=%YYYY%%MM%%DD%"
set "destino=%baseDestino%\%HOY%"
set "logFile=%logFolder%\backup-%HOY%.log"
set "zipFile=%zipFolder%\Backup-%HOY%.zip"
set "hashFile=%zipFolder%\Backup-%HOY%.sha256.txt"

for %%D in ("%baseDestino%" "%zipFolder%" "%logFolder%") do if not exist "%%~D" mkdir "%%~D"
if not exist "%destino%" mkdir "%destino%"

echo ================================================== >> "%logFile%"
echo Inicio: %date% %time% >> "%logFile%"
echo Origen: %origen% >> "%logFile%"
echo Destino: %destino% >> "%logFile%"

REM ======== CONSTRUIR PARAMETROS DE EXCLUSION ========
set "EXCLUDE_PARAMS="
for %%X in (%EXCL_DIRS%) do set "EXCLUDE_PARAMS=!EXCLUDE_PARAMS! /XD ""%%~X"""
for %%X in (%EXCL_FILES%) do set "EXCLUDE_PARAMS=!EXCLUDE_PARAMS! /XF ""%%~X"""

REM ======== COPIA CON ROBOCOPY ========
REM /E copia subcarpetas incluidas vacías; /COPY:DAT datos, atributos y tiempo
REM /DCOPY:T conserva timestamps de directorios; /Z reiniciable; /R:3 reintentos; /W:5 espera
REM /MT:16 multihilo; /XJ evita bucles por junctions; /FFT tolerancia timestamps (NAS)
set "ROBO_OPTS=/E /COPY:DAT /DCOPY:T /Z /R:3 /W:5 /MT:16 /XJ /FFT /NP /NFL /NDL"
echo Ejecutando Robocopy... >> "%logFile%"
robocopy "%origen%" "%destino%" %ROBO_OPTS% %EXCLUDE_PARAMS% /TEE /LOG+:"%logFile%"
set "RC=%ERRORLEVEL%"

REM Códigos de Robocopy: 0,1 = OK; >=8 = error.
if %RC% GEQ 8 (
  echo [ERROR] Robocopy devolvio %RC%. >> "%logFile%"
  goto :fin
) else (
  echo Robocopy finalizado con codigo %RC%. >> "%logFile%"
)

REM ======== COMPRESION ZIP (PowerShell) ========
echo Comprimiendo a ZIP: "%zipFile%" >> "%logFile%"
powershell -NoProfile -Command ^
  "Try {
     Add-Type -AssemblyName 'System.IO.Compression.FileSystem';
     if (Test-Path -LiteralPath '%zipFile%'){ Remove-Item -LiteralPath '%zipFile%' -Force }
     [System.IO.Compression.ZipFile]::CreateFromDirectory('%destino%', '%zipFile%');
     'ZIP creado correctamente' | Out-File -FilePath '%logFile%' -Append -Encoding utf8
   } Catch {
     'ERROR ZIP: ' + $_.Exception.Message | Out-File -FilePath '%logFile%' -Append -Encoding utf8; exit 1 }"
if errorlevel 1 (
  echo [ERROR] Fallo al crear ZIP. >> "%logFile%"
  goto :fin
)

REM ======== HASH (opcional) ========
if "%GENERAR_HASH%"=="1" (
  echo Generando SHA256... >> "%logFile%"
  powershell -NoProfile -Command ^
    "$h=Get-FileHash -LiteralPath '%zipFile%' -Algorithm SHA256; $h.Hash + '  ' + (Split-Path '%zipFile%' -Leaf) | Out-File -FilePath '%hashFile%' -Encoding ascii; 'SHA256 listo' | Out-File -FilePath '%logFile%' -Append -Encoding utf8"
)

REM ======== LIMPIEZA POR RETENCION ========
echo Limpiando elementos con mas de %diasRetencion% dias... >> "%logFile%"
powershell -NoProfile -Command ^
  "Try {
     $limit=(Get-Date).AddDays(-%diasRetencion%);
     Get-ChildItem -LiteralPath '%baseDestino%' -Directory | Where-Object { $_.LastWriteTime -lt $limit } | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue;
     Get-ChildItem -LiteralPath '%zipFolder%' -File | Where-Object { $_.LastWriteTime -lt $limit } | Remove-Item -Force -ErrorAction SilentlyContinue;
     'Limpieza completada' | Out-File -FilePath '%logFile%' -Append -Encoding utf8
   } Catch {
     'ERROR LIMPIEZA: ' + $_.Exception.Message | Out-File -FilePath '%logFile%' -Append -Encoding utf8 }"

REM ======== FIN OK ========
:fin
echo Fin: %date% %time% >> "%logFile%"

REM Registra evento en el Visor (opcional)
REM eventcreate /T INFORMATION /ID 1000 /L APPLICATION /SO RobocopyBackup /D "Backup %HOY% finalizado (RC=%RC%)"

exit /b %RC%
Lenguaje del código: PHP (php)

Consejo: prueba primero con /L (modo simulación) para ver qué copiaría Robocopy sin tocar nada.


Programarlo en el Programador de tareas

  1. Abre Programador de tareasCrear tarea…
  2. Desencadenadores: diario a las 20:00 (o tras el cierre).
  3. Acciones:
    • Programa: C:\Windows\System32\cmd.exe
    • Argumentos: /c "D:\Backups\robocopy_backups.bat"
  4. Condiciones: desmarca “Detener si pasa a batería” si es portátil y te interesa que corra igual.
  5. Configuración: marca “Detener si se ejecuta más de X horas” (p.e. 6 h) y “Si la tarea ya se está ejecutando, no iniciar una instancia nueva”.

Si lo prefieres, puedo darte un .xml listo para importar con un horario concreto.


Restauración (el día que toque)

  1. Localiza el ZIP del día (o la carpeta del día si conservas copias sin comprimir).
  2. Verifica el hash (si generas .sha256):
    • PowerShell: Get-FileHash .\Backup-YYYYMMDD.zip -Algorithm SHA256 y compara con el TXT.
  3. Descomprime en una carpeta de staging y revisa estructura y permisos.
  4. Copia de vuelta lo necesario (o usa Robocopy /MIR con cuidado si quieres espejo).

Exclusiones útiles (evita ruido y ciclos)

  • Carpetas: .git, node_modules, .cache, AppData\Local\Temp, System Volume Information, $Recycle.Bin.
  • Ficheros: Thumbs.db, *.tmp, *.log~, *.etl.
  • Evitas copiar basura, temporales y junctions que pueden multiplicar volumen o hacer bucles.

Seguridad y cumplimiento

  • Cifrado: Compress-Archive/Zip .NET no encripta. Si necesitas cifrado AES-256, usa 7-Zip (CLI) y protege con contraseña (gestión segura).
  • Ransomware: los backups locales pueden verse comprometidos si la máquina se infecta. Valora un disco externo rotativo (conectar, hacer copia, desconectar) o un destino NAS con cuentas separadas y versión inmutable si es posible.
  • Privilegios: si necesitas copiar con privilegios de backup, ejecuta la tarea con una cuenta que tenga el privilegio “Back up files and directories” y usa /B.
  • VSS (archivos en uso): para snapshots consistentes de bases de datos, combina con diskshadow o procesos específicos de tu software contable/ERP.

Rendimiento

  • Hilo múltiple /MT:16 es un buen equilibrio en HDD/NAS. En SSD/NVMe y red rápida puedes subir a 32 o 64.
  • NAS/SMB: añade /IPG:10 si saturas la red en horas punta.
  • Incrementales reales: Robocopy ya omite lo igual, pero si quieres espejo 1:1 usa /MIR (con cautela: también borra en destino lo que se borra en origen).

Monitorización y alertas

  • Los códigos de salida de Robocopy son muy informativos: 0/1 OK, >= 8 error.
  • Puedes enviar correo en caso de error con PowerShell (requiere un SMTP confiable).
  • O lanzar un evento de Windows (ya te dejé eventcreate comentado).

Casos de uso reales

  • Autónomos: respaldo diario en un USB 3.0 rotativo (L-V), zip con fecha y 30 días de retención.
  • Gestorías: copia cada noche a NAS + zip, con exclusiones de temporales y verificación por hash; VSS semanal para ficheros en uso.
  • Micropymes: backup local + sincronización diferencial semanal a un NAS en otra planta.

Preguntas frecuentes

¿Sirve para “incrementales”?
Robocopy omite lo que no ha cambiado; en la práctica, verás que sólo copia lo nuevo/modificado. Si necesitas versiones históricas por archivo, entonces evalúa Historial de archivos o un versionado en NAS.

¿Y si mi ZIP supera 4 GB?
El ZIP de .NET soporta >4 GB. Si necesitas partir en trozos, usa 7-Zip (7z a -v2g ...) y conserva índices.

¿Cómo lo paro si se cuelga?
Configura en el Programador el tiempo máximo, y añade /TBD (espera unidades) sólo si te hace falta. En red inestable, reduce /R y /W.

¿Se puede subir encriptado a la nube?
Sí. Cifra con 7-Zip o un contenedor (p.ej. VeraCrypt) y sincroniza con tu herramienta de confianza. Cuidado con costes y RGPD.


Código fuente

El repositorio original que mencionas:
GitHub: https://github.com/albertlopezespinosa/Robocopy

Suscríbete al boletín SysAdmin

Este es tu recurso para las últimas noticias y consejos sobre administración de sistemas, Linux, Windows, cloud computing, seguridad de la nube, etc. Lo enviamos 2 días a la semana.

¡Apúntate a nuestro newsletter!


– patrocinadores –

Noticias destacadas

– patrocinadores –

¡SUSCRÍBETE AL BOLETÍN
DE LOS SYSADMINS!

Scroll al inicio
×