El Blog de Gualtrysoft

Windows 2000/2003/2008, Active Directory, VBScript, Hyper-V, PowerShell y todo aquello interesante a la hora de usar, configurar y administrar Windows Server. También tenemos longanizas…

Script Para Copiar Directorios (A Modo De Backup)

Posted by urpiano en Miércoles 1 \01\UTC noviembre \01\UTC 2006

Este script permite establecer una lista de directorios de origen y destino, siendo copiados los de origen en el destino correspondiente. Se copian el propio directorio y sus subdirectorios y ficheros contenido, así como sus ACLs. Esto permite realizar la típica “copia de seguridad” que se realiza copiando en un disco los contenidos destinados a “backapear el temporal” :-))

'Este script realiza una copia (usando XCOPY) de los directorios que se le
'cargan en un objeto diccionario. Conserva el propietario y las ACLs de los
'ficheros y carpetas copiados. La copia es realizada según el día de la semana,
'en tres directorios diferentes, especificados por las constantes PATH_LUNES,
'PATH_MARTES y PATH_MIERCOLES. El progreso de las tareas lo vuelca en los ficheros
'log especificados por las constantes LOG_LUNES, LOG_MARTES y LOG_MIERCOLES.
'El script copia en los mismos directorios los lunes y jueves, martes y viernes y
'miércoles y sábado; fácilmente se puede retocar para que se realice la copia en
'un directorio diferente para cada día de la semana

'El script recibe de parámetro la letra de unidad en la que se copiarán los ficheros

'Este script lo creé ante la necesidad de realizar las “copias de seguridad” en un disco
'duro USB, y decidí que lo mejor sería utilizar XCOPY, pues ya que se usa un disco duro
'como soporte para la copia, el tamaño del disco duro de destino era muy grande (suficiente
'para contener más tres veces los datos de origen) y esto permitiría una restauración de
'de datos rapidísima. El script recibe el parámetro pues cada semana escribe la copia
'en un disco distinto.

'Por supuesto, espero la llegada de una unidad de cinta para hacer las copias "como Dios manda"
' ;o))

'©Fernando Reyes López – Abril de 2006

'Constantes para el fichero log, según día de la semana
Const LOG_LUNES = "c:backup-Lunes-Jueves.log"
Const LOG_MARTES = "c:backup-Martes-Viernes.log"
Const LOG_MIERCOLES = "c:backup-Miercoles-Sabado.log"

'Constantes de carpeta de destino según día de la semana
Const PATH_LUNES = "Lunes-Jueves"
Const PATH_MARTES = "Martes-Viernes"
Const PATH_MIERCOLES = "Miercoles-Sabado"

'Definición de variables
Dim dic_Rutas 'Objeto diccionario con las rutas de origen y destino
Dim str_Ruta 'Contendrá las claves del objeto diccionario
Dim str_Unidad 'Letra de unidad de disco de destino (ej. f:)
Dim int_Carpeta 'Contador de carpetas para recorrer los arrays
Dim str_RutaDestino 'ruta de destino de la copia
Dim str_Log 'Ruta + Nombre del fichero Log
Dim obj_FS 'Objeto FileSystem
Dim obj_Log 'Objeto TextStream

'**************** Bloque de verificación de parámetro **********************
'Revisamos que se haya pasado el parámetro de unidad de disco

'Se tiene que pasar un único parámetro; en caso de no ser así
'se termina la ejecución del script
If Not WScript.Arguments.Count = 1 Then

Call s_Error("Error 1: Falta el parámetro de unidad")
WScript.Quit 1

End If

'Revisamos ahora que el parámetro pasado pertenece a una unidad existente
'Para ello lo primero es crear un objeto FileSystem, que se utilizará más
'adelante para crear el fichero Log y un objeto TextXtream con el que pondremos
'el encabezado del fichero Log
Set obj_FS = CreateObject("Scripting.FileSystemObject")

If Not obj_FS.DriveExists(WScript.Arguments(0)) Then

Call s_Error("Error 2: La unidad recibida como parámetro no existe")
WScript.Quit 2

Else

'Todo ha ido correcto y asignamos el valor del parámetro a la variable
'str_Unidad
str_Unidad = WScript.Arguments(0)

End If
'**************** Fin del bloque de verificación de parámetro *****************

'En este bloque Select Case estableceremos el valor de las variables de ruta
'de destino y fichero log en función del día de la semana

Select
Case Weekday(Now)

Case vbTuesday, vbFriday

'Si estamos en martes o viernes significa que estamos lanzando la copia
'de seguridad del lunes o jueves
str_RutaDestino = PATH_LUNES
str_Log = LOG_LUNES

Case vbWednesday, vbSaturday

'Si estamos en miércoles o sábado significa que estamos lanzando la copia
'de seguridad del martes o viernes
str_RutaDestino = PATH_MARTES
str_Log = LOG_MARTES

Case vbThursday, vbSunday

'Si estamos en jueves o domingo significa que estamos lanzando la copia
'de seguridad del miércoles o sábado
str_RutaDestino = PATH_MIERCOLES str_Log = LOG_MIERCOLES


Case
Else

Call s_Error("Error 3: Hoy no toca realizar la copia")
WScript.Quit 3

End Select

'Creamos el fichero de Log cargándolo en el objeto TextStream
Set obj_Log = obj_FS.CreateTextFile(str_log, True)
'Cerramos el fichero log
obj_Log.Close
'Vaciamos los objetos TextStream y FileSystem
Set obj_Log = Nothing
Set obj_FS = Nothing

Call s_EscribeLog( _
      "********************************************************************************" & _
     vbCrLf & "Backup iniciado el " & FormatDateTime(Date, vbLongDate) & " a las " & _
     FormatDateTime(Time, vbLongTime), str_Log)

'Creamos un objeto diccionario y establecemos comparación en modo texto (ignora mayúsculas-minúsculas)
Set dic_Rutas = CreateObject("Scripting.Dictionary")
dic_Rutas.CompareMode = vbTextCompare

'Cargamos el objeto diccionario con las rutas de origen y destino
Call s_CargaRutas(dic_Rutas)

'Escribimos el encabezado del log
Call s_EscribeLog( _
     "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" & _
     vbCrLf & "Eliminando la carpeta """ & str_Unidad & str_RutaDestino & _
     """, que tenía el backup anterior, a las " & FormatDateTime(Time, vbLongTime) & "", str_Log)

'Borramos el backup viejo
Call s_Cmd("rmdir """ & str_Unidad & str_RutaDestino & """ /Q /S",str_Log)
'Escribimos el separador de bloque, pues iniciamos la copia de carpetas
Call s_EscribeLog( _
     "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", _
     str_log)
Call s_EscribeLog("Se inicia la copia de las carpetas de origen en la ruta de destino", str_log)

'En este bucle recorremos las claves del objeto diccionario
For Each str_Ruta In dic_Rutas.Keys

Call s_XCopy(str_Ruta, str_Unidad & str_RutaDestino & "" & _
dic_Rutas(str_Ruta), str_log)

Next

'Escribimos el separador de bloque, para acontinuación escribir el pie del log
Call s_EscribeLog( _
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", _
str_log)
Call s_EscribeLog("Backup finalizado el " & FormatDateTime(Date, vbLongDate) & _
          " a las " & FormatDateTime(Time, vbLongTime) & "", str_log)
          Call s_EscribeLog( _
"********************************************************************************", _
str_log)

Sub s_XCopy(str_Origen, str_Destino, str_Log)
'Esta rutina recibe una ruta de origen, una de destino y realiza un coia del origen en el destino
'Esta copia se realiza con ACLs, propiedad, recusividad incluyendo carpetas vacías, archivos de
'sistema archivos ocultos, etc. (mírese en la ayuda de XCOPY)

'Escribe el separador de carpeta y la información de la copia que realizará
Call s_EscribeLog( _
     "——————————————————————————–" & _
     vbCrLf & "Copia de """ & str_Origen & """ iniciada a las " & _
     FormatDateTime(Time, vbLongTime) & "", str_log)
'Realiza la llamada a XCOPY
Call s_Cmd("xcopy.exe """ & _
                    str_Origen & "*.*"" """ & _
                    str_Destino & _
                    """ /S /E /Y /C /H /R /K /O /X /I /Q", str_log)
'Escribe la información de la copia realizada
Call s_EscribeLog("Copia de """ & str_Origen & """ finalizada a las " & _
                              FormatDateTime(Time, vbLongTime) & "", str_log)

End Sub

Sub s_Cmd(str_Comando, str_Log)
'*****************Descripción********************************
'Esta rutina lanza el comando recibido como parámetro como
'si desde una ventana de comandos fuese lanzado. El segundo
'parámetro es la ruta+nombre de el fichero Log en el que se
'escribirá el comando lanzado
'*****************Fin de la descripción**********************

Dim
str_Shell 'Alberga la cadena que permite lanzar
'la ventana de comandos predeterminada
'(COMSPEC)

Dim obj_Shell 'Contiene un objeto Shell

Call s_EscribeLog(str_Comando, str_log)

'Creamos un objeto Shell
Set obj_Shell = CreateObject("Wscript.Shell")

'Obtenemos la cadena que lanza la ventana de comandos
'predeterminada

str_Shell = obj_Shell.Environment("Process").Item("COMSPEC")

'Lanzamos el comando por medio de una llamada al método Run
'del objeto Shell
obj_Shell.Run str_Shell & " /c """ & str_Comando & """", 0, True

End Sub

Sub s_EscribeLog(str_Linea, str_Log)
'Esta rutina recibe una línea que se debe escribir en el fichero de texto cuya
'ruta+nombre está especificada por str_Log

Dim
obj_FS
Dim obj_Log

Set obj_FS = CreateObject("Scripting.FileSystemObject")

Set obj_Log = obj_FS.OpenTextFile(str_Log, 8, False)
obj_Log.WriteLine str_Linea
obj_Log.Close
Set obj_Log = Nothing
Set obj_FS = Nothing

End Sub

Sub s_Error(str_Error)
'Esta rutina muestra el mensaje de error recibido como parámetro y a continuación la
'ayuda del script

Dim
str_Mensaje

str_Mensaje = _
  str_Error & vbCrLf & vbCrLf & vbCrLf & _
  "xcopy.vbs: script que copia una serie de carpetas en la ruta recibida " & _
  "como parámetro. Dependiendo el día de la semana en que se ejecute, " & _
  "borrará y creará una carpeta en la que se copie el origen. Estas " & _
  "carpetas son Lunes-Jueves, Martes-Viernes, Miercoles-Sabado." & _
  "Está pensado para ser ejecutado por la noche, pasadas las 12, de forma" & _
  "que al lanzarlo el martes o viernes copiará en Lunes-Jueves. " & _
  "Dependiendo también del día, generará un fichero Log en la unidad c:" & _
  vbCrLf & vbCrLf & vbCrLf & _
  "Sintaxis:" & vbCrLf & vbCrLf & _
  "cscript xcopy.vbs unidad" & vbCrLf & vbCrLf & _
  "unidad: letra de unidad de disco local en la que se quiere " & _
  "copiar las carpetas de origen. Parámetro requerido." & vbCrLf & _
  vbCrLf & vbCrLf & "Ejemplo: cscript xcopy.vbs f:" & vbCrLf

WScript.Echo str_Mensaje

End Sub

Sub s_CargaRutas(dic_Rutas)

'Esta rutina carga el objeto diccionario recibido con las rutas de origen
'(como Key del diccionario, primer parámetro del método Add) y
'las de destino (como Items del diccionario, segundo parámetro del
'método Add).

'Para añadir o quitar rutas a copiar, basta con quitar las entradas
'dic_Rutas.Add que sobren y/o añadir las que se requieran.

dic_Rutas.Add "e:Sauron", "Sauron"
dic_Rutas.Add "e:\Galadriel", "Galadriel"
dic_Rutas.Add "e:\Tom Bombadil", "Tom Bombadil"
dic_Rutas.Add "e:\Legolas", "Legolas"
dic_Rutas.Add "e:\Saruman", "Saruman"
dic_Rutas.Add "e:\Gimli", "Gimli"
dic_Rutas.Add "e:\Smaug", "Smaug"
dic_Rutas.Add "e:\Ella", "Ella"

End Sub

Fichero VBS: Este es el script. Se debe cambiar la extensión de txt a vbs y ejecutar con cscript

17 comentarios to “Script Para Copiar Directorios (A Modo De Backup)”

  1. Juan Antonio said

    Buenisimo el script, estoy comenzado a programar scripts y me ha ayudado mucho.

    Un 10 o un 12 xDDD

  2. Carlos said

    Hola.

    Me ha venido como anillo al dedo tu script.

    He hecho un par de cambios:
    – Añadir resto de días de la semana
    – No borrar directorio ya que me interesa que sea acumulativo
    – Cambio de parámtros para que entre otras cosas, copie sólo lo que ha cambiado /D

    Tengo una duda:
    Me gustaría que en el log se reflejara lo que suele verse en pantalla mientras se ejecuta el xopy.

    ¿alguna idea de cómo resolver esto?

    GRACIAS.

  3. urpiano said

    Carlos,

    Prueba si te funciona esto:

    En la rutina s_Cmd poner redirección a la llamada al comando:

    obj_Shell.Run str_Shell & " /c """ & str_Comando & """>""c:\mis logs\backup.log""", 0, True

  4. Sergio said

    Antes que nada felicitaciones por el script, por lo que veo funciona bien, solo que yo soy un poco ignorante en esto, puedes decirme como se programa un script, por lo que veo es en VB pero en VB como hago para crear un un nuevo proyecto o script y luego como hago para correrlo o hecharlo a andar, lo pongo en una tarea programada, como un programa cualquiera con un boton le digo que se inicie???, perdona mi ignorancia pero si no pregunto seguire siendo un ignorante, espero me comprendas, muchas gracias.

  5. urpiano said

    Para crear un script basta el bloc de notas y guardarlo con extensión vbs. Para ejecutarlo puedes hacer doble click sobre él, si queires que lo ejecute WScript.exe,en cuyo caso los mensajes salen cajas de mensaje, una por cada WScript.Echo que se haga, o ejecutarlo con CScript.exe, en cuyo caso los mensajes salen por la ventana de comandos, una línea por cada WScript.Echo que se haga. Respecto a aprender, lo mejor es que te pases por el Script Center

  6. Omar said

    Hola, me parece que el script es fabuloso. quiero hacer algo parecido con la diferencia es que quiero copiar un archivo en medio de carpetas, porfa haber si me puedes ayudar

  7. urpiano said

    Omar,

    ¿Puedes explicarte un poco más?

  8. […] a lo mejor te puede ser de utilidad este script: Script Para Copiar Directorios (A Modo De Backup) https://urpiano.wordpress.com/2006/11…r-directorios/ — Un saludo Fernando Reyes [MS MVP] MCSE Windows 2000 / 2003 MCSA Windows Server 2003 […]

  9. jesus said

    hola como harias un script de copie archivos de una unidad a otra

  10. Artgax said

    necesito copiar una carpeta y su contenido a todos los clientes de la red, utilizo SMS 2003, y piuedo crear el paquete para distribuirlo, pero no sé cpoomo hacer el script. Hice algo, no sé si esté bien, porque lo ejecuto y me envia el error de Acceso Denegado, hago la copia en forma manual y si se realiza.

    strComputer = “.”
    Set objWMIService = GetObject(“winmgmts:” & “{impersonationLevel=impersonate}!\\” & strComputer & “\root\cimv2”)
    Const OverwriteExisting = True

    Set objFSO = CreateObject(“Scripting.FileSystemObject”)
    objFSO.CopyFile “\\TERMXSVCSMS01\Packages$\Files\*.*” , “\\” & strComputer & “\c$\Program Files\Trend Micro\OfficeScan Client\” , OverwriteExisting

    …que estará mal?

    Gracias de antemano.

  11. Artgax said

    sé que antes de copiar los archivos debo detener dos servicios de TREND, ya he logrado hacerlo, y he logrado copiar los archivos, pero, no puedo hacer que los servicios inicien nuevamente.

    Aqui esta el Script.
    ————————————————————————–

    strComputer = “.”
    Set objWMIService = GetObject(“winmgmts:” & “{impersonationLevel=impersonate}!\\” & strComputer & “\root\cimv2”)
    Set objFSO = CreateObject(“Scripting.FileSystemObject”)

    ‘—————————- DETIENE SERVICIOS —————————-

    Set objScanListenerService = objWMIService.Get(“Win32_Service.Name=’tmlisten'”)
    Return = objScanListenerService.StopService()
    Set objNTRTScanService = objWMIService.Get(“Win32_Service.Name=’ntrtscan'”)
    Return = objNTRTScanService.StopService()

    ‘———————–COPIA DE ARCHIVOS EN DESTINO —————————–
    ‘Set objFSO = CreateObject(“Scripting.FileSystemObject”)

    Const OverwriteExisting = True
    objFSO.CopyFile “\\TERMXSVCSMS01\Packages$\Files\*.*” , “\\” & strComputer & “\c$\Program Files\Trend Micro\OfficeScan Client” , OverwriteExisting

    ‘———————–INICIA SERVICIOS —————————————

    Set colServiceList = objWMIService.ExecQuery(“Associators of ” & “{Win32_Service.Name=’tmlisten’} Where ” & “AssocClass=Win32_DependentService ” & “Role=Dependent” )

    ‘Inicia Servicio
    For Each objService in colServiceList
    Return = objService.StartService()
    Next

    Set colServiceList2 = objWMIService.ExecQuery(“Associators of ” & “{Win32_Service.Name=’ntrtscan’} Where ” & “AssocClass=Win32_DependentService ” & “Role=Dependent” )

    ‘Inicia Servicio
    For Each objService in colServiceList2
    WScript.Echo “Starting ” & objService.Name
    Next

    Wscript.Echo “Terminado”
    —————————————–

    Ojalá puedas ayudarme.

    gracias.

  12. IkiruMind said

    Hola Urpiano (oráculo),

    No tengo ni idea de como programar un script, se lo que es, para que se utilizan, pero al haberme iniciado hace poco… estoy perdido.

    Quiero conseguir hacer una cosa, te explico:

    – Tengo una partición de disco (Y:) en la cual se conectan varios empleados.
    – La gente va guardando cosas, y el espacio libre en disco lógicamente va bajando.
    – Quiero crear un “script” que me muestre todo lo que se va generando a diario (archivos etc…) y su tamaño.
    – Así podré saber que documento, archivo, carpeta o lo que sea… hizo bajar tanto el espacio libre del disco.

    Me explico, o me he vuelto loco? Es posible hacerlo? Puedes decirme por donde deberia empezar, o como debria hacerlo, por favor?

    Grácias por tu tiempo.

  13. FernandoL said

    Muy bien por el script, solo tuve un problema que se volvia a llamar a si solo, cuando llegaba el turno de ejecutar xcopy (en lugar de ejecutar el xcopy.exe, se volvia a llamar a si solo, es decir al xcopy.vbs). Para solucionar: cambie el nombre de xcopy.vbs a xcopy1.vbs (por ej); o agregar en la llamada al Xcopy del DOS, la extensión .exe para que no se llame a si mismo.

    Otra cuestion es que voy a ver es que si puedo enviar el log por mail. Me contacto si soluciono.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

 
A %d blogueros les gusta esto: