# FSLogix VHDX Auto-Resize Script mit Mail-Benachrichtigung # Prüft alle Profile und vergrößert automatisch wenn > 85% voll # # Einrichtung: # 1. Skript anpassen (Pfade, Mail-Einstellungen) # 2. Speichern unter C:\Scripts\FSLogix-AutoResize.ps1 # 3. Log-Ordner anlegen: mkdir C:\Logs # 4. Scheduled Task erstellen (siehe unten) # # Scheduled Task per PowerShell erstellen: # $action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File C:\Scripts\FSLogix-AutoResize.ps1" # $trigger = New-ScheduledTaskTrigger -Daily -At "06:00" # $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest # Register-ScheduledTask -TaskName "FSLogix AutoResize" -Action $action -Trigger $trigger -Principal $principal #region Konfiguration # ============================================================================ # HIER ANPASSEN # ============================================================================ # Pfad zu den FSLogix Profilen $ProfilePath = "\\fileserver\FSLogix\Profiles" # Ab welchem Füllstand vergrößern (in Prozent) $ThresholdPercent = 85 # Um wie viel GB vergrößern $GrowByGB = 10 # Maximale Größe (Obergrenze) $MaxSizeGB = 100 # Log-Datei $LogFile = "C:\Logs\FSLogix-AutoResize.log" # Mail-Konfiguration $MailSettings = @{ SmtpServer = "mail.example.de" # SMTP-Server Port = 587 # 587 für STARTTLS, 465 für SSL, 25 für unverschlüsselt UseSsl = $true # SSL/TLS verwenden Username = "monitoring@example.de" # SMTP-Benutzername Password = "DEIN-PASSWORT-HIER" # SMTP-Passwort From = "monitoring@example.de" # Absender To = "admin@example.de" # Empfänger (mehrere: "a@x.de","b@x.de") } # ============================================================================ # AB HIER NICHTS MEHR ÄNDERN # ============================================================================ #endregion #region Funktionen function Write-Log { param( [string]$Message, [string]$Level = "INFO" ) # Log-Verzeichnis erstellen falls nicht vorhanden $logDir = Split-Path -Path $LogFile -Parent if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null } $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $logEntry = "[$Level] $timestamp - $Message" # In Datei schreiben $logEntry | Out-File -FilePath $LogFile -Append -Encoding UTF8 # Auch auf Konsole ausgeben switch ($Level) { "ERROR" { Write-Host $logEntry -ForegroundColor Red } "WARNING" { Write-Host $logEntry -ForegroundColor Yellow } "RESIZE" { Write-Host $logEntry -ForegroundColor Green } default { Write-Host $logEntry } } } function Send-AlertMail { param( [string]$Subject, [string]$Body ) try { $securePassword = ConvertTo-SecureString $MailSettings.Password -AsPlainText -Force $credential = New-Object System.Management.Automation.PSCredential ($MailSettings.Username, $securePassword) $mailParams = @{ SmtpServer = $MailSettings.SmtpServer Port = $MailSettings.Port UseSsl = $MailSettings.UseSsl Credential = $credential From = $MailSettings.From To = $MailSettings.To Subject = $Subject Body = $Body BodyAsHtml = $true Encoding = [System.Text.Encoding]::UTF8 } Send-MailMessage @mailParams Write-Log "Mail erfolgreich gesendet: $Subject" } catch { Write-Log "Mail-Versand fehlgeschlagen: $_" -Level "ERROR" } } function Get-HtmlReport { param( [array]$Warnings, [array]$Resizes, [array]$Errors ) $html = @"

🗄️ FSLogix Auto-Resize Report

Server: $env:COMPUTERNAME
Zeitpunkt: $(Get-Date -Format "dd.MM.yyyy HH:mm:ss")
Profilpfad: $ProfilePath
"@ # Zusammenfassung $html += "

Zusammenfassung: " $summaryParts = @() if ($Resizes.Count -gt 0) { $summaryParts += "✅ $($Resizes.Count) Profile vergrößert" } if ($Warnings.Count -gt 0) { $summaryParts += "⚠️ $($Warnings.Count) Warnungen" } if ($Errors.Count -gt 0) { $summaryParts += "❌ $($Errors.Count) Fehler" } $html += ($summaryParts -join " | ") + "

" # Vergrößerte Profile if ($Resizes.Count -gt 0) { $html += @"

✅ Automatisch vergrößerte Profile

"@ foreach ($r in $Resizes) { $html += "" } $html += "
Profil Alte Größe Neue Größe Belegt
$($r.Name)$($r.OldSize) GB$($r.NewSize) GB$($r.UsedPercent)%
" } # Warnungen if ($Warnings.Count -gt 0) { $html += @"

⚠️ Maximum erreicht - Manuelle Prüfung erforderlich!

Diese Profile haben die maximale Größe von $MaxSizeGB GB erreicht und können nicht weiter automatisch vergrößert werden.

"@ foreach ($w in $Warnings) { $html += "" } $html += "
Profil Aktuelle Größe Belegt
$($w.Name)$($w.Size) GB$($w.UsedPercent)%
" } # Fehler if ($Errors.Count -gt 0) { $html += @"

❌ Fehler bei der Verarbeitung

"@ foreach ($e in $Errors) { $html += "" } $html += "
Profil Fehlermeldung
$($e.Name)$($e.Error)
" } # Footer $html += @"
"@ return $html } #endregion #region Hauptlogik Write-Log "=== Starte FSLogix Auto-Resize ===" # Prüfen ob Profilpfad erreichbar if (-not (Test-Path $ProfilePath)) { Write-Log "Profilpfad nicht erreichbar: $ProfilePath" -Level "ERROR" $errorBody = Get-HtmlReport -Warnings @() -Resizes @() -Errors @(@{ Name = "Profilpfad" Error = "Der Pfad $ProfilePath ist nicht erreichbar. Bitte Netzwerkverbindung und Berechtigungen prüfen." }) Send-AlertMail -Subject "FSLogix FEHLER: Profilpfad nicht erreichbar" -Body $errorBody exit 1 } # Arrays für Report $warnings = @() $resizes = @() $errors = @() # Alle VHDX-Dateien finden $vhdxFiles = Get-ChildItem -Path $ProfilePath -Recurse -Filter "*.vhdx" -ErrorAction SilentlyContinue Write-Log "Gefundene Profile: $($vhdxFiles.Count)" foreach ($vhdx in $vhdxFiles) { try { # VHDX mounten (readonly) um Größe zu prüfen $mount = Mount-VHD -Path $vhdx.FullName -ReadOnly -Passthru -ErrorAction Stop $partition = Get-Partition -DiskNumber $mount.DiskNumber | Where-Object { $_.Type -eq "Basic" } if ($partition) { $volume = Get-Volume -Partition $partition $usedPercent = [math]::Round((($volume.Size - $volume.SizeRemaining) / $volume.Size) * 100, 1) $currentSizeGB = [math]::Round($volume.Size / 1GB, 1) Write-Log "Prüfe: $($vhdx.Name) - $usedPercent% belegt ($currentSizeGB GB)" # Dismounten vor möglichem Resize Dismount-VHD -Path $vhdx.FullName # Prüfen ob Schwellwert überschritten if ($usedPercent -ge $ThresholdPercent) { $currentMaxGB = [math]::Round((Get-VHD -Path $vhdx.FullName).Size / 1GB, 1) $newSizeGB = $currentMaxGB + $GrowByGB if ($newSizeGB -le $MaxSizeGB) { # Vergrößern Write-Log "RESIZE: $($vhdx.Name) von $currentMaxGB GB auf $newSizeGB GB" -Level "RESIZE" Resize-VHD -Path $vhdx.FullName -SizeBytes ($newSizeGB * 1GB) $resizes += @{ Name = $vhdx.Name OldSize = $currentMaxGB NewSize = $newSizeGB UsedPercent = $usedPercent } } else { # Maximum erreicht Write-Log "WARNUNG: $($vhdx.Name) hat Maximum ($MaxSizeGB GB) erreicht!" -Level "WARNING" $warnings += @{ Name = $vhdx.Name Size = $currentMaxGB UsedPercent = $usedPercent } } } } else { Dismount-VHD -Path $vhdx.FullName Write-Log "Keine gültige Partition gefunden in: $($vhdx.Name)" -Level "WARNING" } } catch { Write-Log "FEHLER bei $($vhdx.Name): $_" -Level "ERROR" # Sicherstellen dass VHD dismounted ist Dismount-VHD -Path $vhdx.FullName -ErrorAction SilentlyContinue $errors += @{ Name = $vhdx.Name Error = $_.Exception.Message } } } # Mail senden wenn es was zu berichten gibt if ($warnings.Count -gt 0 -or $resizes.Count -gt 0 -or $errors.Count -gt 0) { # Betreff zusammenbauen $subject = "FSLogix Report: " $parts = @() if ($resizes.Count -gt 0) { $parts += "$($resizes.Count) vergrößert" } if ($warnings.Count -gt 0) { $parts += "$($warnings.Count) Warnungen" } if ($errors.Count -gt 0) { $parts += "$($errors.Count) Fehler" } $subject += $parts -join ", " # HTML-Report erstellen und senden $body = Get-HtmlReport -Warnings $warnings -Resizes $resizes -Errors $errors Send-AlertMail -Subject $subject -Body $body } else { Write-Log "Keine Aktionen erforderlich - alle Profile im grünen Bereich" } Write-Log "=== Durchlauf beendet ===" #endregion