Automatizar la transferencia de archivos entre un servidor SFTP y un servidor Linux desde Windows es más fácil de lo que parece. Con WinSCP, PowerShell y el Programador de tareas puedes crear un flujo confiable que mueva datos cada 15 min sin intervención humana.
Visión general
En entornos mixtos donde conviven sistemas Windows y Linux, la sincronización automática de archivos es esencial para procesos de integración, respaldo o ingestión de datos. Este artículo detalla paso a paso cómo:
- Crear un script en PowerShell que use WinSCP para mover (o copiar) archivos de
\\sftp3\sftp\packnet
(/mnt/sftp2/packnet
en el servidor) a/root/mercury/packnet
. - Registrar ese script en el Programador de tareas de Windows para que se ejecute cada 15 min.
- Aplicar buenas prácticas de seguridad, registro y mantenimiento.
Requisitos previos
- Windows 10/11, Windows Server 2016 o posterior.
- WinSCP instalado (incluye:
WinSCP.exe
,WinSCP.com
yWinSCPnet.dll
). - PowerShell 5.1 o PowerShell 7 + (compatible con .NET Standard).
- Credenciales SFTP con permisos de lectura y eliminación en
/mnt/sftp2/packnet
y escritura en/root/mercury/packnet
. - Cuenta de servicio local o de dominio con permiso de «Log on as a batch job». La tarea se ejecutará con este usuario.
Creación del script de PowerShell
Guarda el archivo como C:\Scripts\WinSCP_Copy.ps1
. Dos enfoques son válidos: uno rápido con el intérprete de comandos y otro robusto con la biblioteca .NET.
Método rápido: intérprete de comandos de WinSCP
Ideal para tareas simples. El propio script genera un bloque de órdenes y lo envía a WinSCP.com
en memoria:
$script = @"
option batch on
option confirm off
open sftp://usuario:contraseña@sftp3
mv /mnt/sftp2/packnet/* /root/mercury/packnet/
exit
"@
$winscp = "C:\Program Files (x86)\WinSCP\WinSCP.com"
$script | & $winscp /script=-
Detalles clave:
option batch on
deshabilita cualquier pregunta interactiva.option confirm off
evita confirmaciones al sobrescribir o eliminar.mv
mueve y borra la fuente. Sustitúyelo porget
(download) oput
(upload) si deseas copiar en lugar de trasladar.- El uso de
/script=-
permite pasar el script directamente vía stdin, sin crear archivos temporales.
Método robusto: biblioteca .NET de WinSCP
Recomendado si necesitas validación granular, reintentos o integración con otros módulos.
Add-Type -Path "C:\Program Files (x86)\WinSCP\WinSCPnet.dll"
\$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
Protocol = \[WinSCP.Protocol]::Sftp
HostName = "sftp3"
UserName = "usuario"
Password = "contraseña"
\# Si usas clave privada:
\# SshPrivateKeyPath = "C:\Keys\id\_rsa.ppk"
\# GiveUpSecurityAndAcceptAnySshHostKey = \$true # SOLO LAB / NO PRODUCCIÓN
}
\$session = New-Object WinSCP.Session
try {
\$session.Open(\$sessionOptions)
\# Mueve todos los archivos y conserva estructura
\$transferResult = \$session.MoveFile("/mnt/sftp2/packnet/\*", "/root/mercury/packnet/")
if (\$transferResult.IsSuccess) {
Write-Host "Transferencia completada: \$(\$transferResult.Transfers.Count) elementos."
}
else {
foreach (\$err in \$transferResult.Failures) {
Write-Warning "Error: \$(\$err.Message)"
}
throw "Se detectaron fallos en la transferencia."
}
}
finally {
\$session.Dispose()
}
La clase Session
expone GetFiles
, PutFiles
, MoveFile
, RemoveFiles
y más, lo que brinda máxima flexibilidad.
Ubicación y permisos del script
- Aloja los scripts en
C:\Scripts
o en un recurso compartido con control de versiones (Git, DevOps). - Otorga a la cuenta que ejecutará la tarea permisos «Lectura y Ejecución» sobre la carpeta y «Lectura y Escritura» en la ruta donde se ubiquen los logs.
- Si el script almacena contraseñas en texto claro, restringe su lectura a usuarios administradores o, mejor aún, emplea el Windows Credential Manager.
Configuración de la tarea programada
Desde la Consola del Programador de tareas (taskschd.msc
) crea una nueva tarea con la siguiente configuración:
Elemento | Valor recomendado |
---|---|
Nombre | Transferencia SFTP Packnet |
Usuario | svc_winscp (cuenta de servicio) |
Ejecutar si el usuario inició sesión | No (marca «Ejecutar tanto si…») |
Privilegios | «Ejecutar con los privilegios más altos» |
Desencadenador | Diario a 00:00 → Repetir cada 15 min (Indefinidamente) |
Programa/script | powershell.exe |
Argumentos | -ExecutionPolicy Bypass -File "C:\Scripts\WinSCP_Copy.ps1" |
Iniciar en | C:\Scripts |
Detener si sobrepasa | 30 min (evita solapamiento) |
Reintentos | Reintentar cada 5 min, 3 veces |
Nota: Usar -ExecutionPolicy Bypass
permite ejecutar el script sin firmar. En entornos regulados, firma el script y emplea AllSigned
.
Pruebas y validación
- Abre una consola de PowerShell como el mismo usuario del Programador de tareas y ejecuta manualmente el script:
.\WinSCP_Copy.ps1 -Verbose
. Verifica que no aparezcan cuadros de diálogo y que los archivos se muevan. - Consulta los logs de WinSCP, si los configuraste (
/log=C:\Logs\winscp_$(Get-Date -Format yyyyMMdd).log
). - En el Programador, usa «Ejecutar» y examina el Historial. El código de salida (Column «Resultado de la última ejecución») debe ser
0x0
. - Revisa que el tiempo total de ejecución sea menor a 15 min; si no, ajusta la frecuencia.
Buenas prácticas y depuración
Registrar salida detallada
$logPath = "C:\Logs\winscp$(Get-Date -Format yyyyMMddHHmmss).log"
$scriptBlock = {
param([string]$innerScript)
$innerScript | & "C:\Program Files (x86)\WinSCP\WinSCP.com" /log=$logPath /script=-
}
$script | & $scriptBlock
Gestión de errores
- Para capturar excepciones en la versión .NET, envuelve la lógica en
try / catch
y retorna códigos de error personalizados (exit 10
). - Con
WinSCP.com
agregaoption failonnomatch off
para ignorar un directorio vacío. - Si usas clave SSH, valida huella digital del host para evitar MITM. Ejemplo:
SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx..."
.
Evitar solapamiento de instancias
Si la carga de archivos es impredecible y una ejecución puede extenderse, utiliza:
Register-ScheduledTask -TaskName "Transferencia SFTP Packnet" `
-Settings (New-ScheduledTaskSettingsSet -MultipleInstances IgnoreNew)
Automatización avanzada y escalabilidad
- Variables de entorno: almacena
$env:SFTPUSER
y$env:SFTPPASS
para no hardcodear credenciales. - JSON de parámetros: carga rutas y filtros desde un archivo (
config.json
) y reutiliza el mismo script para múltiples tareas. - Integración continua: añade pruebas Pester que verifiquen que las rutas son accesibles y que WinSCP devuelve 0.
- Notificaciones: envía correo mediante
Send-MailMessage
cuando el número de archivos transferidos sea 0 durante cierto tiempo. - Compatibilidad con FTPS: cambia
Protocol = 'Ftp'
y añadeTlsHostCertificateFingerprint
para conexiones FTPS explícitas.
Preguntas frecuentes
¿Puedo copiar en lugar de mover?
Sí. Sustituye mv
por get
o put
. En la API .NET usa GetFiles
/PutFiles
.
¿Cómo uso autenticación por clave?
Convierte tu clave privada a formato .ppk
con PuTTYgen y añade SshPrivateKeyPath
. Si tu clave tiene frase de paso, agrega PrivateKeyPassphrase
.
¿Qué ocurre si el directorio está vacío?
Añade option failonnomatch off
o comprueba con $session.FileExists
antes de mover. Sin esta opción, WinSCP finaliza con código 1
y la tarea marcará error.
¿Se pueden transferir subcarpetas?
Sí. Usa comodines recursivos (/
) o -filemask=" >0"
en el intérprete. En la API .NET ajusta TransferOptions
con $opts.FileMask
y $opts.PreserveTimestamp
.
¿Cómo rotar los logs?
Incluye la fecha en el nombre del archivo (como en el ejemplo) o ejecuta un script secundario que elimine los registros con antigüedad > 30 días.
Conclusión
Con un script de PowerShell bien estructurado, WinSCP como motor SFTP y el Programador de tareas de Windows como orquestador, obtienes una solución estable y flexible para mover archivos cada 15 min o con la frecuencia que tu flujo de negocio requiera. Invierte tiempo en pruebas y registro; la automatización perfecta no es la que nunca falla, sino la que avisa a tiempo y se autorecupera.