Canalblog
Editer la page Suivre ce blog Administration + Créer mon blog
Des guides, des tutos

Backup VM HyperV en Cluster

Pourquoi ces scripts ?

Les scripts ci-dessous sont utilisés pour automatiser des backups de VM.
Ce sont des VM HyperV, dans un environnement de Cluster.
Je les utilise pour les backups de certaines machines qui peuvent être stoppées quelques minutes sans que cela ne dérange le fonctionnement de ma société.

Le fonctionnement est le suivant :
Le script va chercher sur quel noeud se trouve la VM.
Si elle est éteinte, il ne fait rien. Peut-être la VM est éteinte volontairement (maintenance, machine défectueuse, etc...)
Si elle est allumée, alors il va l'éteindre, copier le VHD, puis la rallumer.
ATTENTION cela ne marche pour l'instant qu'avec les machines virtuelles fonctionnant sous Windows !

Il y a un script dit "principal", qui contient toutes les fonctions.
Ensuite, par VM, il faudra 2 scripts.
Un .PS1, qui contient quelques variables, et un .bat, qui appelle le .PS1.
Je me sert du .bat dan les taches planifiées.

Pour l'exemple, on les nommera comme suit :
Reboot_Fonction.PS1
Ma_Machine.PS1
Ma_Machine.bat


Sur mon serveur, le tout est placé dans C:\Scripts\Backup_VM\

Contenu de Ma_Machine.bat
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "C:\Scripts\Backup_VM\Ma_Machine.ps1"
exit


Vérifiez éventuellement l'emplacement de powershell.exe, sait-on jamais...
Les invites DOS et Powershell s'ouvrent et se ferment relativement vite.
S'il y a un message d'erreur, vous n'aurez pas le temps de les lire.

A ce niveau, dans le .bat, on peut rajouter -noexit ici :

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noexit "C:\Scripts\Backup_VM\Ma_Machine.ps1"

Cela va empêcher la fenêtre de se fermer, sauf manuellement bien sur !

ATTENTION à enlever cette variable lorsque vous automatisez l'exécution avec une tache planifiée !
Sinon, l'instance va rester ouverte, et c'est le début des problèmes..

Contenu de Ma_Machine.PS1
. C:\Scripts\Backup_VM\Reboot_Fonction.ps1
Backup_VM -VMName "Ma_Machine" -Delais 30

exit


Ici, je rentre en variable le nom de VM Ma_Machine. Ce doit être le nom d'une machine virtuelle présente sur votre cluster !
J'insère aussi un délais de 30 secondes, utilisé dans Reboot_Fonction.PS1

Contenu de Reboot_Fonction.PS1

Il vous faudra ici télécharger 2 modules, si vous ne els avez pas déjà.
Il s'agit des modules FailOver et HyperV.

Failover permet d'interroger le cluster et pas un seul serveur physique
Hyperv permet d'éteindre et d'allumer les machines sans SCVMM
Le Module HyperV est téléchargeable ici

#######################Paramétrages#######################
##########################################################
# Paramétrage Dossier
$Cheminscript = "C:\Scripts\Backup_VM"
#Suppression des vieux fichiers
cd $Cheminscript
del dir.txt
#####Informations relative à l'envoi de mail
$expediteur = "user@mon_domaine.com"
$serveur = "172.16.0.67"
$SMTPAuthUsername = "user@mon_domaine.local"
$SMTPAuthPassword = "XXXXXXXX"
$SMTPclient = new-object System.Net.Mail.SmtpClient $serveur
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($SMTPAuthUsername, $SMTPAuthPassword)

#########################Fonction#########################
##########################################################
function Backup_VM($VMName,$Delais){
#Creation du journal de log
$Journal = 'C:\Scripts\Backup_VM\' + $VMName + '.txt'
# Paramétrage Dossier
$Backup = "\\15.15.15.1\d$\Backup\$VMName\"
$Backupdate = (get-date).tostring(‘yyyy-MM-dd’)
$BackupTotal = $Backup+$Backupdate + "\"

"Debut du travail le " + (get-date).tostring(‘dd-MM-yyyy’) + " à " + (get-date).tostring(‘hh:mm:ss’) > $Journal
"" >> $Journal
"-------------------------------------------------------------" >> $Journal
"-------------------------------------------------------------" >> $Journal
"-------------------------------------------------------------" >> $Journal
"" >> $Journal

#Import du module failover -> Ca permet d'interroger le cluster et pas un seul serveur physique
"Import du module FailOver" >> $Journal
Import-Module FailoverClusters
#Import du module Hyperv -> ca permet d'éteindre et d'allumer les machines sans SCVMM
"Import du module HyperV" >> $Journal
Import-Module "C:\Program Files\modules\HyperV\Hyperv.psd1"
"" >> $Journal
"-------------------------------------------------------------" >> $Journal
"-------------------------------------------------------------" >> $Journal
"" >> $Journal

"Recherche du serveur qui heberge la VM dans le cluster à " + (get-date).tostring(‘hh:mm:ss’) >> $Journal
"" >> $Journal
$VMGroups = Get-ClusterGroup | ?{ $_ | Get-ClusterResource | ?{ $_.ResourceType -like "Virtual Machine" }}
$VM = $VMGroups | Where-Object {$_.Name -eq $VMName}
$ServerSource = $VM.ownernode.name
"Serveur détenant la VM au moment de l'exécution du script : $ServerSource" >> $Journal
"" >> $Journal
"-------------------------------------------------------------" >> $Journal
"-------------------------------------------------------------" >> $Journal
"" >> $Journal

"Localisation du VHD et test de présence d'un AVHD à " + (get-date).tostring(‘hh:mm:ss’) >> $Journal
$VHDLocation = Get-VMDisk "$VM" -server "$ServerSource" | Where-Object {$_.DriveName -eq "Disque Dur"}
$VHDFileName = $VHDLocation.diskPath
$VHDFileImage = $VHDLocation.diskimage
"Présence des fichiers suivants (SI VHD UNIQUEMENT, LE NOM EST EN DOUBLE) : " >> $Journal
"" >> $Journal
"$VHDFileName" >> $Journal
"$VHDFileImage" >> $Journal
"" >> $Journal
"-------------------------------------------------------------" >> $Journal
"-------------------------------------------------------------" >> $Journal
"" >> $Journal

#Inscription en variable du chemin physique du VHD, volume 1 ou 2
if ($VHDFileName -like '*Volume1*')
{$Chemin = "C:\ClusterStorage\Volume1\$VmName\" }
else
{$Chemin = "C:\ClusterStorage\Volume2\$VmName\" }
"" >> $Journal
"Chemin Physique de la VM : $Chemin" >> $Journal
"" >> $Journal
"-------------------------------------------------------------" >> $Journal
"-------------------------------------------------------------" >> $Journal
"" >> $Journal

"Envoi du mail au service Info sur le traitement effectué à " + (get-date).tostring(‘hh:mm:ss’) >> $Journal
if (($VHDFileName -like '*.avhd') -and ($VM | Where-Object {$_.State -eq "Online"}))
{
"La VM est allumée, un AVHD est présent, on ne fait rien au niveau du script de sauvegarde." >> $Journal
$objet = "HyperV - Sauvegarde de $VMName - Machine allumée ET AVHD le " + [System.DateTime]::Now
$texte = "La VM $VMName n'a pas été traitée, un fichier AVHD est présent"
}
elseif (($VHDFileName -like '*.avhd') -and ($VM | Where-Object {$_.State -eq "Offline"}))
{
"La VM est éteinte, un AVHD est présent, on ne fait rien au niveau du script de sauvegarde." >> $Journal
$objet = "HyperV - Sauvegarde de $VMName - Machine éteinte ET AVHD le " + [System.DateTime]::Now
$texte = "La VM $VMName n'a pas été traitée, un fichier AVHD est présent"
}
elseif (($VHDFileName -like '*.vhd') -and ($VM | Where-Object {$_.State -eq "Online"}))
{
"Arret de la VM à " + (get-date).tostring(‘hh:mm:ss’) >> $Journal
shutdown-vm -vm "$VM" -server "$ServerSource" -force
"" >> $Journal
"Ajout d'un délais pour laisser a la VM le temps de s'éteindre" >> $Journal
ping 127.0.0.1 -n $Delais
"" >> $Journal
foreach ($DisqueVHD in $VHDFileName){
"Début du compactage du VHD à " + (get-date).tostring(‘hh:mm:ss’) >> $Journal
Compact-VHD $DisqueVHD -wait
"Fin du compactage du VHD à " + (get-date).tostring(‘hh:mm:ss’) >> $Journal
"" >> $Journal
"Début de la copie du VHD à " + (get-date).tostring(‘hh:mm:ss’) >> $Journal
"" >> $Journal
xcopy $DisqueVHD $BackupTotal /Y >> $Journal
"" >> $Journal
"Fin de la copie du VHD à " + (get-date).tostring(‘hh:mm:ss’) >> $Journal
"" >> $Journal
}
"Démarrage de la VM à " + (get-date).tostring(‘hh:mm:ss’) >> $Journal
start-vm -vm "$VM" -server "$ServerSource" >> $Journal
"" >> $Journal
"" >> $Journal
"-------------------------------------------------------------" >> $Journal
"-------------------------------------------------------------" >> $Journal
"-------------------------------------------------------------" >> $Journal

$objet = "HyperV - Sauvegarde de $VMName - Opération réussie le " + [System.DateTime]::Now
$texte = "La VM $VMName a été copiée. Vous trouverez le journal de Log en PJ."
ls $Backup | select -exp Name > dir.txt
foreach ($files in ${C:\Scripts\Backup_VM\dir.txt}) {
$Asupprimer = $Backup + $files
Remove-Item -recurse $Asupprimer -exclude $Backupdate
}
}
elseif (($VHDFileName -like '*.vhd') -and ($VM | Where-Object {$_.State -eq "Offline"}))
{
"La VM est éteinte, peut-être volontairement, on ne fait rien au niveau du script de sauvegarde." >> $Journal
$objet = "HyperV - Sauvegarde de $VMName - Machine Eteinte le " + [System.DateTime]::Now
$texte = "La VM $VMName est éteinte. La sauvegarde n'a pas eu lieu."
}
"Fin du travail à " + (get-date).tostring(‘hh:mm:ss’) >> $Journal
foreach ($email in ${C:\Scripts\Backup_VM\mailrecap.txt}) {
$destinataire = $email
$message = new-object System.Net.Mail.MailMessage $expediteur, $destinataire, $objet, $texte
$attachment = new-object System.Net.Mail.Attachment $Journal
$message.Attachments.Add($attachment)
$SMTPclient.Send($message)
}
}
Publicité
Publicité
Des guides, des tutos
  • Quelques guides informatiques variés, pour les novices et les plus calés. N'hésitez pas à laisser des commentaires, si vous voyez des corrections ou des améliorations à apporter, vous êtes les bienvenus !
  • Accueil du blog
  • Créer un blog avec CanalBlog
Publicité
Archives
Publicité