Utilisation de backuppc avec Windows 7 et VSS (shadow copy)

Sous backuppc, les utilisateurs peuvent être avertis d’une erreur de sauvegarde des fichiers Outlook lorsque leur poste est sauvegardé par smb. Mais je voulais profiter de la rapidité et de la sécurité de SSH couplé à Rsync. Le problème de cette solution est que les fichiers ouverts, tout comme en sauvegardant en smb, no peuvent pas être sauvegardés.

Mon but est donc de procéder comme suit :

  • création d’une volume shadow copy puis montage de volume avant la sauvegarde
  • sauvegarde du postes par SSH/Rsync
  • démontage et suppression de la volume shadow copy

Cette solution a les avantages :

  • d’une sauvegarde rapide
  • d’avoir une communication cryptée
  • de sauvegarder tous les fichiers, même ceux qui sont verouillés

Les points négatifs sont :

  • une installation assez lourde (Cygwin, scripts, exe) que je vais essayer d’optimiser/automatiser
  • une difficulté pour restaurer les fichiers à leur emplacement d’origine en effet les fichiers sont sauvegardés depuis un dossier monté spécialement (exemple : c:\shadow\C).

I – Copie du fichier vshadow.exe

Le fichier vshadow.exe est l’exécutable utilisé pour gérer les clichés instantanés.

Afin d’éviter d’installer le SDK, voilà une archive regroupant les fichiers vshadow pour Windows XP, Vista, 7, 2003, 2008 et 2008 R2 : vshadow versions

Je copie ce fichier dans le dossier c:\shadow\

2 – Installation de Cygwin et paramétrage de l’authentification par clef publique

a – Installer Cygwin avec les paquets suivants :

  • nano
  • rsync
  • openssh
  • cygrunsrv

Accepter l’installation des paquets dépendants.

Créer l’utilisateur qui sera utilisé pour effectuer les sauvegardes, je vais créer l’utilisateur backuppc et lui donner un mot de passe.
Se reconnecter au PC sous ce nouveau compte et exécuter cygwin en tant qu’admin (clic droi, exécuter…).

Lancez les commandes suivantes :

ssh-host-config -y
cygrunsrv -S sshd

b – Ajout de la clef publique

Depuis le serveur connectez-vous en ssh à la machine en train d’installer :

# faire un cat de la clef publique et copier cette ligne
su backuppc
ssh nomdelamachine
# entrer le mot de passe de l'utilisateur backuppc
nano /home/backuppc/.ssh/authorized_keys
# coller la ligne de la clef publique, bien vérifier que tout soit sur une seule ligne et enregistrer le fichier

Essayez de vous connecter à nouveau, cette fois aucun mot de passe ne devrait être demandé, en effet la clef publique sera utilisée pour la connexion

c – Eviter l’expiration du mot de passe des comptes Windows créés

Sur une ligne de commande classique exécutée en tant qu’admin, lancez les commandes suivantes afin de désactiver l’expiration des mots de passes des comptes cyg_server et backuppc :

wmic path Win32_UserAccount where Name='backuppc' set PasswordExpires=false
wmic path Win32_UserAccount where Name='cyg_server' set PasswordExpires=false

3 – Scripts pour l’utilisation de VSS

a – Fichier VssSnapshot.vbs

Un script doit être mis en place sur la machine, je me suis inspiré du script disponible sur cette page.

Mais je l’ai simplifié pour les test, seul le volume shadow de C est monté. De plus j’avais un bloquage au moment de démonter l’image j’ai dont ajouté quelques lignes pour éviter ce blocage.

Mon script vssShadow.vbs à placer sur chaque poste sauvegardé dans le dossier C:\shadow\

''# VssSnapshot.vbs
''# http://serverfault.com/questions/119120/how-to-use-a-volume-shadow-copy-to-make-backups/119592#119592
Option Explicit

Dim fso: Set fso = CreateObject("Scripting.FileSystemObject")

''# -- MAIN SCRIPT -------------------------------------------
Dim args, snapshotId, targetPath, success, vshadowPath
Set args = WScript.Arguments.Named
vshadowPath = "C:\shadow"
CheckEnvironment

Log "preparing VSS mount point..."
targetPath = PrepareVssMountPoint(args("target"))

If args.Exists("unmount") Then
Log "nothing else to do"
ElseIf targetPath <> vbEmpty Then
Log "mount point prepared at: " & targetPath
Log "creating VSS snapshot for volume: " & args("volume")
snapshotId = CreateVssSnapshot(args("volume"))

If snapshotId <> vbEmpty Then
Log "snapshot created with ID: " & snapshotId
success = MountVssSnapshot(snapshotId, targetPath)
If success Then
Log "VSS snapshot mounted sucessfully"
Else
Die "failed to mount snapshot"
End If
Else
Die "failed to create snapshot"
End If
Else
Die "failed to prepare mount point"
End If

Log "finished"

''# -- FUNCTIONS ---------------------------------------------
Function PrepareVssMountPoint(target) ''# As String
Dim cmd, result, outArray
Dim path, snapshot, snapshotId
Dim re, matches, match

PrepareVssMountPoint = VbEmpty
target = fso.GetAbsolutePathName(target)

If Not fso.FolderExists(fso.GetParentFolderName(target)) Then
Die "Invalid mount point: " & target
End If

''# create or unmount (=delete existing snapshot) mountpoint
If Not fso.FolderExists(target) Then
If Not args.Exists("unmount") Then fso.CreateFolder target
Else

Set re = New RegExp
re.MultiLine = False
re.Pattern = "- Exposed locally as: ([^\r\n]*)"

cmd = vshadowPath & "vshadow -q"

result = RunCommand(cmd, false)

outarray = Split(result, "*")

For Each snapshot In outArray
snapshotId = ParseSnapshotId(snapshot)
If snapshotId <> vbEmpty Then
Set matches = re.Execute(snapshot)
If matches.Count = 1 Then
path = Trim(matches(0).SubMatches(0))
If fso.GetAbsolutePathName(path) = target Then
cmd = vshadowPath & "vshadow -ds=" & snapshotId
RunCommand cmd, true
Exit For
End If
End If
End If
Next

If args.Exists("unmount") Then fso.DeleteFolder target
End If

PrepareVssMountPoint = target
End Function

Function CreateVssSnapshot(volume) ''# As String
Dim cmd, result

If Not fso.DriveExists(volume) Then
Die "Drive " & volume & " does not exist."
End If

cmd = vshadowPath & "vshadow -p " & Replace(UCase(volume), ":", "") & ":"
result = RunCommand(cmd, false)
CreateVssSnapshot = ParseSnapshotId(result)
End Function

Function MountVssSnapshot(snapshotId, target) ''# As Boolean
Dim cmd, result

If fso.FolderExists(targetPath) Then
cmd = vshadowPath & "vshadow -el=" & snapshotId & "," & targetPath
result = RunCommand(cmd, true)
Else
Die "Mountpoint does not exist: " & target
End If

MountVssSnapshot = (result = "0")
End Function

Function ParseSnapshotId(output) ''# As String
Dim re, matches, match

Set re = New RegExp
re.Pattern = "SNAPSHOT ID = (\{[^}]{36}\})"
Set matches = re.Execute(output)

If matches.Count = 1 Then
ParseSnapshotId = matches(0).SubMatches(0)
Else
ParseSnapshotId = vbEmpty
End If
End Function

Function RunCommand(cmd, exitCodeOnly) ''# As String
Dim shell, process, output

Dbg "Running: " & cmd

Set shell = CreateObject("WScript.Shell")

On Error Resume Next

Set process = Shell.Exec(cmd)

If Err.Number <> 0 Then
Die Hex(Err.Number) & " - " & Err.Description
End If
On Error GoTo 0

If Not cmd = vshadowPath & "vshadow -q" Then
Do While process.Status = 0
WScript.Sleep 100
Loop
End If
output = Process.StdOut.ReadAll

If process.ExitCode = 0 Then
Dbg "OK"
Dbg output
Else
Dbg "Failed with ERRORLEVEL " & process.ExitCode
Dbg output
If Not process.StdErr.AtEndOfStream Then
Dbg process.StdErr.ReadAll
End If
End If

If exitCodeOnly Then
Runcommand = process.ExitCode
Else
RunCommand = output
End If
End Function

Sub CheckEnvironment
Dim argsOk

If LCase(fso.GetFileName(WScript.FullName)) <> "cscript.exe" Then
Say "Please execute me on the command line via cscript.exe!"
Die ""
End If

argsOk = args.Exists("target")
argsOk = argsOk And (args.Exists("volume") Or args.Exists("unmount"))

If Not argsOk Then
Say "VSS Snapshot Create/Mount Tool" & vbNewLine & _
vbNewLine & _
"Usage: " & vbNewLine & _
"cscript /nologo " & fso.GetFileName(WScript.ScriptFullName) & _
" /target:path { /volume:X | /unmount } [/debug]" & _
vbNewLine & vbNewLine & _
"/volume  - drive letter of the volume to snapshot" & _
vbNewLine & _
"/target  - the path (absolute or relative) to mount the snapshot to" & _
vbNewLine & _
"/debug   - swich on debug output" & _
vbNewLine & vbNewLine & _
"Examples: " & vbNewLine & _
"cscript /nologo " & fso.GetFileName(WScript.ScriptFullName) & _
" /target:C:\Backup\DriveD /volume:D" &  vbNewLine & _
"cscript /nologo " & fso.GetFileName(WScript.ScriptFullName) & _
" /target:C:\Backup\DriveD /unmount" & _
vbNewLine & vbNewLine & _
"Hint: No need to unmount before taking a new snapshot." & vbNewLine

Die ""
End If
End Sub

Sub Say(message)
If message <> "" Then WScript.Echo message
End Sub

Sub Log(message)
Say FormatDateTime(Now()) & " " & message
End Sub

Sub Dbg(message)
If args.Exists("debug") Then
Say String(75, "-")
Say "DEBUG: " & message
End If
End Sub

Sub Die(message)
If message <> "" Then Say "FATAL ERROR: " & message
WScript.Quit 1
End Sub

Il faut créer deux script utilisés par backuppc avant et après la sauvegarde afin de gérer le volume shadow copy.

Mon plus gros problème aura été de trouver pourquoi vshadow faisait des erreurs à chaque exécution depuis backuppc, cela est causé par le fait que lorsqu’un se connecte à Cygwin par ssh en authentification par clef, l’utilisateur n’est pas authentifié comme l’utilisateur normal mais comme le compte système. De ce fait, ce compte ne dispose pas des droits de gestion de VSS.

Une authentification est donc obligatoire. N’ayant rien trouvé dans le man ssh je me suis tourné vers expect qui permet d’automatiser des enchaînements de commandes.

b – Fichier pre-backuppc.sh

Script sur le serveur utilisé avant la sauvegarde (/home/backuppc/pre-backuppc.sh chez moi) :

#!/usr/bin/expect -f

set force_conservative 1;
set USER [lindex $argv 0]
set HOST [lindex $argv 1]
set timeout 30
spawn ssh -o PubkeyAuthentication=no $USER@$HOST "cscript.exe /nologo c:\\\\shadow\\\\vssSnapshot.vbs /target:C:\\\\shadow\\\\C /volume:C /debug\r"
expect "password:\r"
send -- "motdepasse\r"
set timeout 500
expect OEF

c – Fichier post-backuppc.sh

Script sur le serveur utilisé après la sauvegarde (/home/backuppc/post-backuppc.sh chez moi) :

#!/usr/bin/expect -f

set force_conservative 1;
set USER [lindex $argv 0]
set HOST [lindex $argv 1]
set timeout 30
spawn ssh -o PubkeyAuthentication=no $USER@$HOST "cscript.exe /nologo c:\\\\shadow\\\\vssSnapshot.vbs /target:C:\\\\shadow\\\\C /unmount \r"
expect "*password:*"
send -- "motdepasse\r"
set timeout 500
expect OEF

4 – Optimisations et corrections de problèmes

– Autoriser les réponses ICMP dans le firewall afin de pouvoir faire un ping

– Ajouter au moins les droits de lecture à l’utilisateur backuppc sur les dossiers/fichiers à sauvegarder

– Sous Windows XP vérifier que les services suivants sont bien en démarrage automatiques et sont démarrés :

  • MS Software Shadow Copy Provider
  • Volume Shadow Copy

Si il y a un pbl avec la création d’un utilisateur lancer la commande

mkpasswd.exe > /etc/passwd

Si impossible de se connecter avec l’utilisateur backuppc essayer la commande ssh-user-config

Masquer les comptes utilisés par Cygwin et backuppc

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList]
"backuppc"=dword:00000000
"cyg_server"=dword:00000000

 

Quelques tutos qui m’ont aidé :

2 réflexions au sujet de « Utilisation de backuppc avec Windows 7 et VSS (shadow copy) »

  1. Bonjour,
    votre article est très interessant. Je me demande néanmoins de quels manières sot lancés les scripts pre et post backup?

    Je vous remercie d’avance pour votre réponse.

  2. Bonjour,

    Les scripts sont lancés par backuppc dans la page « Backup Settings » et dans les champs DumpPreUserCmd et DumpPostUserCmd.

    Les scripts sont appelés avec une ligne type :
    – pour le prebackup : /etc/backuppc/pre-backuppc.sh utilisateur $host motdepasse lecteuràsauvegarder
    – post backup : /etc/backuppc/post-backuppc.sh utilisateur $host motdepasse lecteuràsauvegarder

    Exemple avec de vraies valeurs : /etc/backuppc/pre-backuppc.sh backuppc $host supermotdepasse C

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*