#Script créé par Nicolas Lang - Sous licence CC-BY-SA #https://nicolaslang.fr param( [int]$joursprochains = 0 ) #Ce paramètre vous permettra de choisir sur combien de jours vous souhaitez analyser les sauvegardes #Le serveur SMTP pour l'envoi du mail $mailserver = "smtpserver.domain.local" #L'expéditeur $from = "moi@domain.local" #Le / Les destinateurs $to = @("moi@domain.local","lui@domain.local","eux@autredomaine.fr") #On démarre un fichier de log, utile en cas de problème Start-Transcript C:\Temp\BECheck.txt -Force #On essaie d'importer le module BEMCLI. S'il n'existe pas, alors on arrête le script try { Import-Module BEMCLI } catch { Write-Output "Impossible d'importer le module BEMCLI" throw("No BEMCLI") exit } #Un peu de texte pour alimenter le fichier de log if ($joursprochains -ne 0) { Write-Output "$((get-date).tolongtimestring()) : Vérification pour les $joursprochains prochains jours." } Write-Output "$((get-date).tolongtimestring()) : Récupération de l'objet de librairie" #On essaie d'obtenir l'objet de libraire. Si c'est impossible, on coupe. try { $librairie = Get-BERoboticLibraryDevice } catch { Write-Output "$((get-date).tolongtimestring()) : Impossible de récupérer la libraire : $($Error[0])" throw("Library error") exit } # On essaie ensuite de récuperer la liste des backups. Si une erreur se présente, on coupe. try { $listofjobs = Get-BEJob -JobType "Backup" } catch { Write-Output "$((get-date).tolongtimestring()) : Impossible de récuperer les jobs : $($error[0])" throw("Backup error") exit } #region inventaire #Lancement d'un inventaire. Si pas d'inventaire... et bien... la aussi, on coupe. try { $inventory = Submit-BEInventoryJob -RoboticLibraryDevice $librairie } catch { Write-Output "$((get-date).tolongtimestring()) : Une erreur s'est produite durant le lancement de l'inventaire : $($Error[0])" throw("Inventory error") exit } #Attente du lancement du job d'inventaire #L'outil BEMCLI est assez mal concu sur certains points. Il y a un décallage entre le lancement de l'inventaire et sa détection dans les jobs actifs. #Nous devons donc attendre que l'inventaire déclenché précedemment soit détecté et actif. Write-Output "Attente du lancement du job`n" do { try { $jobcheck = Get-BEActiveJobDetail } catch { Write-host -NoNewline "-" } $jobfinished = Get-BEJobHistory -FromStartTime (get-date).Date | Where-Object {$_.name -eq $($inventory.name)} Start-Sleep -Seconds 10 Write-Host -NoNewline "-" } until($jobcheck.Name -eq $inventory.Name -or $jobfinished -ne $null) Write-host " " #Couleurs jolies pour patienter. Oui. Comme ça. $i = 1 $z = 15 Write-Host $(" " * $((get-host).ui.rawui.buffersize.width)) -BackgroundColor 15 Write-Host "Attente de la fin du job d'inventaire" Write-Host $(" " * $((get-host).ui.rawui.buffersize.width)) -BackgroundColor 15 do { if ($i % $((get-host).UI.RawUI.BufferSize.Width) -eq 0) { if ($z -eq 0){$z = 16} $z-- Write-host " " -BackgroundColor $z } else { Write-Host -NoNewline " " -BackgroundColor $z } $i++ Start-Sleep -Seconds 1 $endofjob = Get-BEJobHistory -FromStartTime (get-date).Date | Where-Object {$_.name -eq $($inventory.name)} }while ($endofjob -eq $null) #Si le job n'est pas en succès, on coupe la et on avertit. Sinon, on continue. if ($endofjob.JobStatus -ne "Succeeded") { Write-Output "$((get-date).tolongtimestring()) : Fin de l'inventaire." Send-MailMessage -From $from -To $to -SmtpServer $mailserver -Subject "Erreur durant l'inventaire" -Body [string]($endofjob | ConvertTo-Html) -BodyAsHtml Stop-Transcript throw("ERREUR DURANT L'INVENTAIRE") Exit } Write-Output "$((get-date).tolongtimestring()) : Fin de l'inventaire." #endregion #Récupération du pool de media géré par BE. Nous recalculons à l'aide d'une propriété dynamique la date car elle est au format texte. #Nous en aurons besoin au format DateTime pour pouvoir faire le tri. Write-output "$((get-date).tolongtimestring()) : Récupération des médias gérés par BE." try { $mediapool = (get-bemedia) | Select-Object Name,AllocatedDate,@{Name = "Date ajoutable";Expression = {Get-date $_.AppendableUntilDate}} | Sort-Object "date ajoutable" -Descending } catch { Write-output "$((get-date).tolongtimestring()) : Erreur lors de la récupération du pool de médias : $($error[0])" } #Récupération du contenu de l'autoloader. Write-output "$((get-date).tolongtimestring()) : Récupération du contenu de l'autoloader." try { $slots = Get-BERoboticLibrarySlot -RoboticLibraryDevice $librairie -IsCleaningSlot $false } catch { Write-output "$((get-date).tolongtimestring()) : Erreur lors de la récupération des slots de la librairie : $($Error[0])" } #Récupération des jobs dont le prochain démarrage est entre aujourd'hui et le nombre de jours précisé. $jobrunningtoday = $listofjobs | Where-Object {($_.nextstartdate.date -ge (get-date).Date -and $_.nextstartdate.date -le (get-date).AddDays($joursprochains).Date)} | Select-Object Name,Storage,nextStartDate if ($jobrunningtoday -eq $null) { Write-output "$((get-date).tolongtimestring()) : Aucune sauvegarde detectée. Fin du script" throw("No backup") exit } $tapedefinitions = New-Object System.Collections.ArrayList $validtapes = New-Object System.Collections.ArrayList $analysed = @() # Dans la liste des jobs qui seront lancés, nous récupérons l'emplacement utilisé dans la librairie et vérifions le nombre de cassettes sur lequel nous pouvons écrire. foreach ($job in $jobrunningtoday) { if ($job.storage -notin $analysed) { $analysed += $job.storage $slots = Get-BERoboticLibrarySlot -RoboticLibraryPartition $job.storage foreach ($tape in $slots) { try { $writedate = $($($mediapool | Where-Object {$_.name -eq $tape.media})."date ajoutable" | Sort-Object -Property "date ajoutable" -Descending) | Select-Object -First 1 -ErrorAction Stop } catch { Write-Host "Pas de date d'écriture sur une cassette" $writedate = get-date "01/01/2001" } $tapedefinitions.Add([PSCUSTOMOBJECT]@{ "Media" = $tape.Media "Slot" = $tape.SlotNumber "Storage" = $job.storage "Ecrasable" = $writedate }) | Out-Null } try { $toadd = $($tapedefinitions | Where-Object {$_.storage -eq $job.storage -and $_.ecrasable -lt $job.nextstartdate -and $_.media -and $_.media -ne $null}) foreach ($addit in $toadd) { $validtapes.add($addit) | Out-Null } } catch { Write-output "$((get-date).tolongtimestring()) : Détection d'une erreur sur l'ajout de $($toadd.media) dans la liste des cassettes valides" } } } $groupedjobs = $jobrunningtoday | Group-Object Storage $groupedtapes = $validtapes | Group-Object Storage $errorarray = New-Object System.Collections.ArrayList # En fonction de si l'on a le nombre précis de cassettes necessaires pour les sauvegardes (Ex : 2 backups a faire et 2 cassettes à disposition), # nous affichons un message d'alerte. # Si c'est un nombre inférieur, nous affichons une erreur foreach ($line in $groupedjobs) { $oktapes = $($groupedtapes | Where-Object {$_.name -eq $line.name}) if ($line.count -gt $oktapes.count) { $errorarray.Add([PSCUSTOMOBJECT]@{ "Niveau" = "DANGER" "Erreur" = "$($line.count) sauvegardes ($($line.Group.name)) dans les logements $($line.name), mais seulement $($oktapes.Count) disponible(s) $($oktapes.group.media)" }) } elseif ($line.count -eq $oktapes.count) { $errorarray.Add([PSCUSTOMOBJECT]@{ "Niveau" = "Avertissement" "Erreur" = "Juste assez de cassettes disponibles en écriture dans les logements $($line.name) pour faire la/les sauvegarde(s) $($line.Group.name). Si une sauvegarde demande plus d'une cassette, une sera bloquée en attente de média!" }) } } #Et nous envoyons le mail avec toutes les informations nécessaires $body = "" $subject = "Liste des cassettes" $priority = "Normal" if ($errorarray.Count -gt 0) { $subject = "!!DANGER SUR LES PROCHAINES SAUVEGARDES!!" $priority = "High" $body += $errorarray | ConvertTo-Html $body += " "*5 } $choosein = $mediapool | Where-object {$_.name -notin $tapedefinitions.media} | Sort-Object "Date ajoutable" $body += "Liste des cartouches triées par date d'écrasement " $body += $choosein | Select-Object Name,"Date ajoutable" | ConvertTo-Html Send-MailMessage -SmtpServer $mailserver -From $from -To $to -Body $body -BodyAsHtml -Subject $subject -Encoding UTF8 -Priority $priority Stop-Transcript