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
- Copia completa desde origen a carpeta de trabajo del día (timestamp) usando Robocopy.
 - Comprime la copia del día en un 
.zip(uno por día). - Limpieza de backups antiguos (tanto carpetas como ZIP) según retención configurable.
 - Logs detallados (+ evento en el Visor de sucesos si quieres).
 - Cálculo de duración y código de salida claro para integrarlo con monitorización.
 - 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:Tpara directorios,/XJpara 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
.dshcondiskshadowo awbadmin. 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
- Abre Programador de tareas → Crear tarea…
 - Desencadenadores: diario a las 20:00 (o tras el cierre).
 - Acciones:
- Programa: 
C:\Windows\System32\cmd.exe - Argumentos: 
/c "D:\Backups\robocopy_backups.bat" 
 - Programa: 
 - Condiciones: desmarca “Detener si pasa a batería” si es portátil y te interesa que corra igual.
 - 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
.xmllisto para importar con un horario concreto.
Restauración (el día que toque)
- Localiza el ZIP del día (o la carpeta del día si conservas copias sin comprimir).
 - Verifica el hash (si generas 
.sha256):- PowerShell: 
Get-FileHash .\Backup-YYYYMMDD.zip -Algorithm SHA256y compara con el TXT. 
 - PowerShell: 
 - Descomprime en una carpeta de staging y revisa estructura y permisos.
 - Copia de vuelta lo necesario (o usa Robocopy 
/MIRcon 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 
diskshadowo procesos específicos de tu software contable/ERP. 
Rendimiento
- Hilo múltiple 
/MT:16es un buen equilibrio en HDD/NAS. En SSD/NVMe y red rápida puedes subir a 32 o 64. - NAS/SMB: añade 
/IPG:10si 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,>= 8error. - Puedes enviar correo en caso de error con PowerShell (requiere un SMTP confiable).
 - O lanzar un evento de Windows (ya te dejé 
eventcreatecomentado). 
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