Diese Seite beschreibt die PowerShell-Scripte zur automatisierten Bereitstellung externer Backupmedien für Veeam.
Ziel ist es, die Backupmedien nur für die Dauer des jeweiligen Veeam-Backupjobs verfügbar zu machen und dadurch eine zusätzliche Schutzschicht gegen Ransomware, Fehlbedienung oder versehentliches Löschen zu schaffen.
Es werden zwei externe Sicherungen unterschieden:
J:F:| Sicherung | Anschlussart | Laufwerk | Volume-Label | Bereitstellung |
|---|---|---|---|---|
| Halbjahresbackup | SEH UTN / USB-over-Network | J: | Halbjahres Backup | SEH UTN aktivieren/deaktivieren |
| Jahresbackup | direkt angeschlossene USB-HDD | F: | Jahres Backup | Windows-Disk online/offline setzen |
J: implementiertUniqueId vorgesehenF: implementiert1. Veeam BackupCopy-Job startet
2. Pre-Script SEH-UTN-Mount.ps1 wird ausgeführt
3. SEH UTN-Port wird aktiviert
4. Windows erkennt das USB-Backupmedium
5. Script wartet auf Volume-Label Halbjahres Backup
6. Laufwerksbuchstabe J: wird gesetzt
7. Veeam schreibt die Backupdaten auf das Zielrepository
8. Nach Abschluss startet das Post-Script SEH-UTN-Unmount.ps1
9. SEH UTN-Port wird deaktiviert
10. Laufwerk J: verschwindet aus Windows
11. Backupmedium ist im Normalbetrieb nicht erreichbar
1. Veeam BackupCopy-Job startet
2. Pre-Script Jahresbackup-Mount.ps1 wird ausgeführt
3. Jahresbackup-Disk wird anhand der Disk UniqueId gesucht
4. Disk wird online gesetzt
5. ggf. wird der ReadOnly-Status entfernt
6. Script wartet auf Volume-Label Jahres Backup
7. Laufwerksbuchstabe F: wird gesetzt
8. Veeam schreibt die Backupdaten auf das Zielrepository
9. Nach Abschluss startet das Post-Script Jahresbackup-Unmount.ps1
10. Jahresbackup-Disk wird offline gesetzt
11. Laufwerk F: ist im Normalbetrieb nicht verfügbar
Durch die zeitlich begrenzte Aktivierung der Backupmedien sind die externen Sicherungen nicht dauerhaft als beschreibbare Laufwerke im System verfügbar.
Das reduziert das Risiko durch:
Beim Halbjahresbackup wird das Medium über SEH UTN getrennt. Für Windows wirkt dies ähnlich wie ein entferntes USB-Gerät.
Beim Jahresbackup bleibt die HDD physisch angeschlossen, wird jedoch Windows-seitig offline gesetzt. Dadurch ist sie im Normalbetrieb nicht als Laufwerk verwendbar.
Wichtig: Diese Lösung stellt eine zusätzliche Schutzschicht dar, ersetzt jedoch kein vollständiges physisches Air-Gap. Für maximalen Schutz sollten externe Backupdatenträger zusätzlich räumlich getrennt gelagert werden.
Weitere Übersicht: siehe Diagramme & Ablauf
| Zweck | Pfad |
|---|---|
| Halbjahresbackup Mount-Script | C:\Scripts\Veeam\SEH-UTN-Mount.ps1 |
| Halbjahresbackup Unmount-Script | C:\Scripts\Veeam\SEH-UTN-Unmount.ps1 |
| Jahresbackup Mount-Script | C:\Scripts\Veeam\Jahresbackup-Mount.ps1 |
| Jahresbackup Unmount-Script | C:\Scripts\Veeam\Jahresbackup-Unmount.ps1 |
| SEH UTN Manager | C:\Program Files\SEH Computertechnik GmbH\SEH UTN Manager\utnm.exe |
| Parameter | Wert |
|---|---|
| Anschluss | SEH UTN |
| SEH UTN IP-Adresse | 192.168.1.179 |
| SEH UTN Port | 1 |
| Laufwerk | J: |
| Volume-Label | Halbjahres Backup |
| Bereitstellung | per SEH UTN activate/deactivate |
| Parameter | Wert |
|---|---|
| Anschluss | direkt angeschlossene USB-HDD |
| Laufwerk | F: |
| Volume-Label | Jahres Backup |
| Bereitstellung | Windows-Disk online/offline |
| Identifikation | Disk UniqueId |
Die Disk UniqueId der Jahresbackup-HDD muss einmalig ermittelt und in den beiden Jahresbackup-Scripten hinterlegt werden.
Ausführen, solange die Jahresbackup-HDD online und als F: verfügbar ist:
$label = "Jahres Backup"
$vol = Get-Volume -FileSystemLabel $label
$part = Get-Partition -Volume $vol
Get-Disk -Number $part.DiskNumber | Format-List Number,FriendlyName,SerialNumber,UniqueId,BusType
Dokumentation:
| Feld | Wert |
|---|---|
| Volume-Label | Jahres Backup |
| Laufwerk | F: |
| Disk UniqueId | 3E543148324B4333 |
| Seriennummer | 00000000NT1H2KC3 |
| Hersteller / Modell | Seagate Expansion HDD |
| Kapazität | 9 TB |
| Aufbewahrungsort | Im Serverraum, am Server |
Die Scripte werden im jeweiligen Veeam-Job als Pre- und Post-Scripte hinterlegt.
Typischer Pfad in der Veeam-Oberfläche:
Job bearbeiten
→ Storage
→ Advanced
→ Scripts
→ Run the following script before the job
→ Run the following script after the job
| Script-Typ | Pfad |
|---|---|
| Pre-Script | C:\Scripts\Veeam\SEH-UTN-Mount.ps1 |
| Post-Script | C:\Scripts\Veeam\SEH-UTN-Unmount.ps1 |
| Script-Typ | Pfad |
|---|---|
| Pre-Script | C:\Scripts\Veeam\Jahresbackup-Mount.ps1 |
| Post-Script | C:\Scripts\Veeam\Jahresbackup-Unmount.ps1 |
# SEH UTN Mount - Halbjahresbackup
$SehExe = "C:\Program Files\SEH Computertechnik GmbH\SEH UTN Manager\utnm.exe"
$UtnIp = "192.168.1.179"
$UtnPort = 1
$DriveLetter = "J"
$VolumeLabel = "Halbjahres Backup"
$Timeout = 60
Write-Host "Aktiviere SEH UTN..."
if (-not (Test-Path $SehExe)) {
Write-Host "FEHLER: utnm.exe wurde nicht gefunden: $SehExe" -ForegroundColor Red
exit 100
}
& $SehExe /c "activate $UtnIp $UtnPort" /q /nw
if ($LASTEXITCODE -ne 0) {
Write-Host "FEHLER: UTN-Aktivierung fehlgeschlagen. ExitCode: $LASTEXITCODE" -ForegroundColor Red
exit $LASTEXITCODE
}
Write-Host "Warte auf Volume '$VolumeLabel'..."
$deadline = (Get-Date).AddSeconds($Timeout)
$vol = $null
while ((Get-Date) -lt $deadline) {
$vol = Get-Volume -FileSystemLabel $VolumeLabel -ErrorAction SilentlyContinue
if ($vol) { break }
Start-Sleep -Seconds 2
}
if (-not $vol) {
Write-Host "FEHLER: Volume '$VolumeLabel' nicht gefunden." -ForegroundColor Red
exit 10
}
if (@($vol).Count -gt 1) {
Write-Host "FEHLER: Mehrere Volumes mit Label '$VolumeLabel' gefunden." -ForegroundColor Red
exit 12
}
$existing = Get-Volume -DriveLetter $DriveLetter -ErrorAction SilentlyContinue
if ($existing -and $existing.FileSystemLabel -ne $VolumeLabel) {
Write-Host "FEHLER: $DriveLetter`: ist bereits belegt durch '$($existing.FileSystemLabel)'." -ForegroundColor Red
exit 11
}
$part = Get-Partition -Volume $vol
if ($part.DriveLetter -ne $DriveLetter) {
Write-Host "Setze Laufwerksbuchstaben auf $DriveLetter`: ..."
Set-Partition -DiskNumber $part.DiskNumber -PartitionNumber $part.PartitionNumber -NewDriveLetter $DriveLetter
}
if (Test-Path "$DriveLetter`:\") {
Write-Host "Fertig. Laufwerk $DriveLetter`: ist bereit." -ForegroundColor Green
exit 0
}
Write-Host "FEHLER: Laufwerk $DriveLetter`: nicht erreichbar." -ForegroundColor Red
exit 1
# SEH UTN Unmount - Halbjahresbackup
$SehExe = "C:\Program Files\SEH Computertechnik GmbH\SEH UTN Manager\utnm.exe"
$UtnIp = "192.168.1.179"
$UtnPort = 1
$DriveLetter = "J"
$VolumeLabel = "Halbjahres Backup"
$Timeout = 30
Write-Host "Pruefe Laufwerk $DriveLetter`: ..."
if (-not (Test-Path $SehExe)) {
Write-Host "FEHLER: utnm.exe wurde nicht gefunden: $SehExe" -ForegroundColor Red
exit 100
}
$vol = Get-Volume -DriveLetter $DriveLetter -ErrorAction SilentlyContinue
if (-not $vol) {
Write-Host "Laufwerk $DriveLetter`: ist bereits nicht verbunden." -ForegroundColor Green
exit 0
}
if ($vol.FileSystemLabel -ne $VolumeLabel) {
Write-Host "FEHLER: $DriveLetter`: ist vorhanden, hat aber falsches Label: '$($vol.FileSystemLabel)'." -ForegroundColor Red
exit 11
}
Write-Host "Trenne SEH UTN..."
& $SehExe /c "deactivate $UtnIp $UtnPort" /q /nw
if ($LASTEXITCODE -ne 0) {
Write-Host "FEHLER: UTN-Deaktivierung fehlgeschlagen. ExitCode: $LASTEXITCODE" -ForegroundColor Red
exit $LASTEXITCODE
}
Write-Host "Warte auf Entfernen von Laufwerk $DriveLetter`: ..."
for ($i = 1; $i -le $Timeout; $i++) {
$vol = Get-Volume -DriveLetter $DriveLetter -ErrorAction SilentlyContinue
```
if (-not $vol) {
Write-Host "Fertig. Laufwerk $DriveLetter`: wurde entfernt." -ForegroundColor Green
exit 0
}
Start-Sleep -Seconds 1
```
}
Write-Host "FEHLER: Laufwerk $DriveLetter`: ist nach der Deaktivierung noch vorhanden." -ForegroundColor Red
exit 1
Wichtig: Vor Nutzung muss HIER-DEINE-DISK-UNIQUEID-EINTRAGEN durch die tatsächliche Disk UniqueId der Jahresbackup-HDD ersetzt werden.
# Jahresbackup HDD Mount
$DiskUniqueId = "HIER-DEINE-DISK-UNIQUEID-EINTRAGEN"
$DriveLetter = "F"
$VolumeLabel = "Jahres Backup"
$Timeout = 30
$disk = Get-Disk | Where-Object { $_.UniqueId -eq $DiskUniqueId }
if (-not $disk) {
Write-Host "FEHLER: Jahresbackup-Disk nicht gefunden." -ForegroundColor Red
exit 10
}
if (@($disk).Count -gt 1) {
Write-Host "FEHLER: Mehrere Disks mit dieser UniqueId gefunden." -ForegroundColor Red
exit 13
}
if ($disk.IsOffline) {
Write-Host "Setze Disk online..."
Set-Disk -Number $disk.Number -IsOffline $false
}
if ($disk.IsReadOnly) {
Write-Host "Entferne ReadOnly..."
Set-Disk -Number $disk.Number -IsReadOnly $false
}
$deadline = (Get-Date).AddSeconds($Timeout)
$vol = $null
while ((Get-Date) -lt $deadline) {
$vol = Get-Volume -FileSystemLabel $VolumeLabel -ErrorAction SilentlyContinue
if ($vol) { break }
Start-Sleep -Seconds 2
}
if (-not $vol) {
Write-Host "FEHLER: Volume '$VolumeLabel' nicht gefunden." -ForegroundColor Red
exit 11
}
if (@($vol).Count -gt 1) {
Write-Host "FEHLER: Mehrere Volumes mit Label '$VolumeLabel' gefunden." -ForegroundColor Red
exit 14
}
$existing = Get-Volume -DriveLetter $DriveLetter -ErrorAction SilentlyContinue
if ($existing -and $existing.FileSystemLabel -ne $VolumeLabel) {
Write-Host "FEHLER: $DriveLetter`: ist bereits belegt durch '$($existing.FileSystemLabel)'." -ForegroundColor Red
exit 12
}
$part = Get-Partition -Volume $vol
if ($part.DriveLetter -ne $DriveLetter) {
Write-Host "Setze Laufwerksbuchstaben auf $DriveLetter`: ..."
Set-Partition -DiskNumber $part.DiskNumber -PartitionNumber $part.PartitionNumber -NewDriveLetter $DriveLetter
}
if (Test-Path "$DriveLetter`:\") {
Write-Host "Jahresbackup-Laufwerk $DriveLetter`: ist bereit." -ForegroundColor Green
exit 0
}
Write-Host "FEHLER: Laufwerk $DriveLetter`: nicht erreichbar." -ForegroundColor Red
exit 1
Wichtig: Vor Nutzung muss HIER-DEINE-DISK-UNIQUEID-EINTRAGEN durch die tatsächliche Disk UniqueId der Jahresbackup-HDD ersetzt werden.
# Jahresbackup HDD Unmount
$DiskUniqueId = "HIER-DEINE-DISK-UNIQUEID-EINTRAGEN"
$DriveLetter = "F"
$VolumeLabel = "Jahres Backup"
$disk = Get-Disk | Where-Object { $_.UniqueId -eq $DiskUniqueId }
if (-not $disk) {
Write-Host "FEHLER: Jahresbackup-Disk nicht gefunden." -ForegroundColor Red
exit 10
}
if (@($disk).Count -gt 1) {
Write-Host "FEHLER: Mehrere Disks mit dieser UniqueId gefunden." -ForegroundColor Red
exit 13
}
if ($disk.IsOffline) {
Write-Host "Jahresbackup-Disk ist bereits offline." -ForegroundColor Green
exit 0
}
$vol = Get-Volume -DriveLetter $DriveLetter -ErrorAction SilentlyContinue
if ($vol -and $vol.FileSystemLabel -ne $VolumeLabel) {
Write-Host "FEHLER: $DriveLetter`: hat falsches Label: '$($vol.FileSystemLabel)'." -ForegroundColor Red
exit 11
}
Write-Host "Setze Jahresbackup-Disk offline..."
Set-Disk -Number $disk.Number -IsOffline $true
Start-Sleep -Seconds 2
$diskCheck = Get-Disk | Where-Object { $_.UniqueId -eq $DiskUniqueId }
if ($diskCheck.IsOffline) {
Write-Host "Jahresbackup-Disk wurde offline gesetzt." -ForegroundColor Green
exit 0
}
Write-Host "FEHLER: Disk ist nach Set-Disk noch online." -ForegroundColor Red
exit 1
Falls Veeam PowerShell-Scripte nicht direkt zuverlässig startet, können CMD-Wrapper verwendet werden.
@echo off
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\Veeam\SEH-UTN-Mount.ps1"
exit /b %ERRORLEVEL%
@echo off
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\Veeam\SEH-UTN-Unmount.ps1"
exit /b %ERRORLEVEL%
@echo off
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\Veeam\Jahresbackup-Mount.ps1"
exit /b %ERRORLEVEL%
@echo off
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\Veeam\Jahresbackup-Unmount.ps1"
exit /b %ERRORLEVEL%
Get-Volume -DriveLetter J
Erwartetes Volume-Label:
Halbjahres Backup
Get-Volume -DriveLetter F
Erwartetes Volume-Label:
Jahres Backup
Diskstatus prüfen:
Get-Disk | Format-Table Number,FriendlyName,SerialNumber,UniqueId,BusType,IsOffline,IsReadOnly -AutoSize
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\Veeam\SEH-UTN-Mount.ps1"
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\Veeam\SEH-UTN-Unmount.ps1"
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\Veeam\Jahresbackup-Mount.ps1"
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\Veeam\Jahresbackup-Unmount.ps1"
Nach jedem Halbjahres- oder Jahresbackup sind folgende Punkte zu prüfen:
| Prüfung | Erwarteter Zustand |
|---|---|
| Veeam-Job | Success |
| Pre-Script | ExitCode 0 |
| Post-Script | ExitCode 0 |
| Ziel-Laufwerk während Job verfügbar | Ja |
| Ziel-Laufwerk nach Job entfernt/offline | Ja |
| Backupdaten vorhanden | Ja |
| Repository-Rescan | falls erforderlich erfolgreich |
| Test-Restore | stichprobenartig empfohlen |
| ExitCode | Bedeutung |
|---|---|
0 | Erfolg |
1 | Laufwerk nach Mount nicht erreichbar |
10 | Volume-Label nicht gefunden |
11 | Laufwerksbuchstabe bereits falsch belegt |
12 | Mehrere Volumes mit gleichem Label gefunden |
100 | utnm.exe nicht gefunden |
| ExitCode | Bedeutung |
|---|---|
0 | Erfolg oder Laufwerk bereits getrennt |
1 | Laufwerk nach Deaktivierung noch vorhanden |
11 | Laufwerk vorhanden, aber falsches Volume-Label |
100 | utnm.exe nicht gefunden |
| ExitCode | Bedeutung |
|---|---|
0 | Erfolg |
1 | Laufwerk nach Mount nicht erreichbar |
10 | Disk anhand UniqueId nicht gefunden |
11 | Volume-Label nicht gefunden |
12 | Laufwerksbuchstabe bereits falsch belegt |
13 | Mehrere Disks mit gleicher UniqueId gefunden |
14 | Mehrere Volumes mit gleichem Label gefunden |
| ExitCode | Bedeutung |
|---|---|
0 | Erfolg oder Disk bereits offline |
1 | Disk ist nach Set-Disk noch online |
10 | Disk anhand UniqueId nicht gefunden |
11 | Laufwerk vorhanden, aber falsches Volume-Label |
13 | Mehrere Disks mit gleicher UniqueId gefunden |
* Backupserver oder Ersatzsystem bereitstellen
* SEH UTN-Gerät verfügbar machen
* Halbjahresbackup-HDD über SEH UTN verbinden
* Script SEH-UTN-Mount.ps1 ausführen
* Prüfen, ob J: verfügbar ist
* Veeam öffnen
* Repository rescan oder Backup importieren
* gewünschten Restorepunkt auswählen
* Wiederherstellung starten
* Ergebnis fachlich prüfen
* Backupserver oder Ersatzsystem bereitstellen
* Jahresbackup-HDD anschließen
* Script Jahresbackup-Mount.ps1 ausführen
* Prüfen, ob F: verfügbar ist
* Veeam öffnen
* Repository rescan oder Backup importieren
* gewünschten Restorepunkt auswählen
* Wiederherstellung starten
* Ergebnis fachlich prüfen
* Die Scripte müssen lokal auf dem Veeam-Backupserver liegen.
* Die Scripte benötigen administrative Rechte.
* Der Veeam Backup Service muss die notwendigen Rechte besitzen.
* Laufwerksbuchstaben und Volume-Labels dürfen nicht ohne Anpassung der Scripte geändert werden.
* Die Jahresbackup-HDD muss eindeutig über die Disk UniqueId identifiziert werden.
* Nach jedem Backupjob muss geprüft werden, ob das Medium wieder getrennt bzw. offline ist.
* Für einen höheren Schutzgrad sollten die Datenträger nach erfolgreicher Sicherung zusätzlich physisch getrennt und räumlich separat gelagert werden.
Das Halbjahresbackup wird über SEH UTN nur für den Backupjob verbunden und danach wieder getrennt.
Das Jahresbackup liegt auf einer direkt angeschlossenen USB-HDD, die nur für den Backupjob online gesetzt und danach wieder offline geschaltet wird.
Dadurch sind die externen Sicherungen im Normalbetrieb nicht dauerhaft als aktive Laufwerke verfügbar und bieten eine zusätzliche Wiederherstellungsoption für größere IT-Notfälle.