#requires -version 5.1
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$ErrorActionPreference = "Stop"
$script:DefaultBlockSizesMB = @(8, 32, 64, 128, 256)
$script:DefaultCountdownSeconds = 5
function Write-Section {
param([string]$Text)
Write-Host ""
Write-Host ("=" * 72) -ForegroundColor DarkCyan
Write-Host (" {0}" -f $Text) -ForegroundColor Cyan
Write-Host ("=" * 72) -ForegroundColor DarkCyan
}
function Write-WarnLine {
param([string]$Text)
Write-Host $Text -ForegroundColor Yellow
}
function Write-ErrorLine {
param([string]$Text)
Write-Host $Text -ForegroundColor Red
}
function Write-InfoLine {
param([string]$Text)
Write-Host $Text -ForegroundColor Gray
}
function Read-MenuChoice {
param(
[string]$Prompt,
[string[]]$AllowedValues
)
do {
$value = Read-Host $Prompt
} until ($AllowedValues -contains $value)
return $value
}
function Read-PositiveInt {
param([string]$Prompt)
do {
$value = Read-Host $Prompt
$parsed = 0
$ok = [int]::TryParse($value, [ref]$parsed)
} until ($ok -and $parsed -gt 0)
return $parsed
}
function Read-PositiveDouble {
param([string]$Prompt)
do {
$value = Read-Host $Prompt
$parsed = 0.0
$ok = [double]::TryParse(
$value,
[System.Globalization.NumberStyles]::Float,
[System.Globalization.CultureInfo]::InvariantCulture,
[ref]$parsed
)
if (-not $ok) {
$ok = [double]::TryParse(
$value,
[System.Globalization.NumberStyles]::Float,
[System.Globalization.CultureInfo]::CurrentCulture,
[ref]$parsed
)
}
} until ($ok -and $parsed -gt 0)
return $parsed
}
function Format-Bytes {
param([Int64]$Bytes)
if ($Bytes -ge 1TB) { return "{0:N2} TB" -f ($Bytes / 1TB) }
if ($Bytes -ge 1GB) { return "{0:N2} GB" -f ($Bytes / 1GB) }
if ($Bytes -ge 1MB) { return "{0:N2} MB" -f ($Bytes / 1MB) }
if ($Bytes -ge 1KB) { return "{0:N2} KB" -f ($Bytes / 1KB) }
return "$Bytes Bytes"
}
function New-TimeStampedName {
param(
[string]$Prefix = "disk_fill_test",
[string]$Extension = ".tmp"
)
return "{0}_{1}{2}" -f $Prefix, (Get-Date -Format "yyyyMMdd_HHmmss"), $Extension
}
function Resolve-NormalizedPath {
param([string]$Path)
return [System.IO.Path]::GetFullPath($Path)
}
function Resolve-PathOnDrive {
param(
[string]$InputPath,
[string]$DriveRoot
)
if ([string]::IsNullOrWhiteSpace($InputPath)) {
return (Resolve-NormalizedPath -Path $DriveRoot)
}
if ([System.IO.Path]::IsPathRooted($InputPath)) {
return (Resolve-NormalizedPath -Path $InputPath)
}
return (Resolve-NormalizedPath -Path (Join-Path $DriveRoot $InputPath))
}
function Test-PathOnDrive {
param(
[string]$Path,
[string]$DriveRoot
)
$normalizedPath = Resolve-NormalizedPath -Path $Path
$normalizedRoot = Resolve-NormalizedPath -Path $DriveRoot
if (-not $normalizedRoot.EndsWith("\")) {
$normalizedRoot += "\"
}
return $normalizedPath.StartsWith($normalizedRoot, [System.StringComparison]::OrdinalIgnoreCase)
}
function Get-VolumeMap {
$result = @{}
try {
$partitions = Get-Partition -ErrorAction Stop
foreach ($partition in $partitions) {
if ([string]::IsNullOrWhiteSpace($partition.DriveLetter)) {
continue
}
$driveKey = ("{0}:" -f $partition.DriveLetter.ToUpper())
$disk = $null
try {
$disk = Get-Disk -Number $partition.DiskNumber -ErrorAction Stop
}
catch {
$disk = $null
}
$result[$driveKey] = [PSCustomObject]@{
DriveLetter = $driveKey
DiskNumber = $partition.DiskNumber
Partition = $partition
Disk = $disk
}
}
}
catch {
}
return $result
}
function Get-DriveInventory {
$logicalDisks = Get-CimInstance Win32_LogicalDisk |
Where-Object { $_.DriveType -in 2, 3 } |
Sort-Object DeviceID
$volumeMap = Get-VolumeMap
$inventory = @()
foreach ($ld in $logicalDisks) {
$driveKey = $ld.DeviceID.ToUpper()
$disk = $null
$model = "-"
$busType = "-"
$mediaHint = "Unbekannt"
$isSSD = $false
if ($volumeMap.ContainsKey($driveKey) -and $volumeMap[$driveKey].Disk) {
$disk = $volumeMap[$driveKey].Disk
if ($disk.FriendlyName) { $model = [string]$disk.FriendlyName }
if ($disk.BusType) { $busType = [string]$disk.BusType }
if ($disk.MediaType) { $mediaHint = [string]$disk.MediaType }
if (
([string]$disk.MediaType -match "SSD") -or
([string]$disk.FriendlyName -match "SSD") -or
([string]$disk.FriendlyName -match "NVMe") -or
([string]$disk.BusType -match "NVMe")
) {
$isSSD = $true
}
}
$inventory += [PSCustomObject]@{
DeviceID = $ld.DeviceID
DriveType = $ld.DriveType
VolumeName = $ld.VolumeName
FileSystem = $ld.FileSystem
Size = [Int64]$ld.Size
FreeSpace = [Int64]$ld.FreeSpace
DriveRoot = ($ld.DeviceID + "\")
Model = $model
BusType = $busType
MediaHint = $mediaHint
IsSSD = $isSSD
}
}
return $inventory
}
function Select-Drive {
$drives = Get-DriveInventory
if (-not $drives -or $drives.Count -eq 0) {
throw "Keine lokalen oder wechselbaren Laufwerke gefunden."
}
Write-Section "Laufwerk auswählen"
for ($i = 0; $i -lt $drives.Count; $i++) {
$d = $drives[$i]
$label = if ($d.VolumeName) { $d.VolumeName } else { "-" }
$type = if ($d.DriveType -eq 2) { "Wechselbar" } else { "Lokal" }
$medium = if ($d.IsSSD) { "SSD/NVMe erkannt" } else { $d.MediaHint }
Write-Host ("[{0}] {1} | Label: {2} | Frei: {3} | Gesamt: {4}" -f `
($i + 1), $d.DeviceID, $label, (Format-Bytes $d.FreeSpace), (Format-Bytes $d.Size)) -ForegroundColor Green
Write-Host (" Typ: {0} | Dateisystem: {1} | Bus: {2} | Medium: {3}" -f `
$type, $d.FileSystem, $d.BusType, $medium) -ForegroundColor DarkGray
Write-Host (" Modell: {0}" -f $d.Model) -ForegroundColor DarkGray
}
do {
$choice = Read-Host "`nNummer des Laufwerks wählen"
$parsed = 0
$valid = [int]::TryParse($choice, [ref]$parsed) -and $parsed -ge 1 -and $parsed -le $drives.Count
} until ($valid)
return $drives[$parsed - 1]
}
function Show-DriveWarnings {
param($Drive)
Write-Section "Hinweise"
Write-WarnLine "Mit CTRL+C kann der Test jederzeit abgebrochen werden."
Write-WarnLine "Dieses Skript dient einem Schreib-Stresstest, nicht sicherem Löschen."
if ($Drive.IsSSD) {
Write-WarnLine ("SSD/NVMe erkannt auf {0}. Häufige Vollschreib-Tests erzeugen zusätzliche Schreiblast." -f $Drive.DeviceID)
}
else {
Write-InfoLine ("Medium auf {0}: {1}" -f $Drive.DeviceID, $Drive.MediaHint)
}
if ($Drive.DeviceID -ieq "C:") {
Write-WarnLine "Du hast C: gewählt. Ein Vollschreiben des freien Platzes kann Windows oder laufende Prozesse stören."
}
}
function Get-TargetFolder {
param($Drive)
Write-Section "Zielordner auswählen"
Write-InfoLine ("Enter für Laufwerks-Root: {0}" -f $Drive.DriveRoot)
$inputPath = Read-Host "Zielordner"
$resolvedPath = Resolve-PathOnDrive -InputPath $inputPath -DriveRoot $Drive.DriveRoot
if (-not (Test-Path $resolvedPath)) {
$create = Read-MenuChoice -Prompt "Pfad existiert nicht. Erstellen? (j/n)" -AllowedValues @("j","J","n","N")
if ($create -in @("j","J")) {
New-Item -Path $resolvedPath -ItemType Directory -Force | Out-Null
}
else {
throw "Zielordner existiert nicht."
}
}
if (-not (Test-PathOnDrive -Path $resolvedPath -DriveRoot $Drive.DriveRoot)) {
throw "Der Zielordner muss auf dem gewählten Laufwerk liegen."
}
return (Resolve-Path $resolvedPath).Path
}
function Get-TestFileName {
Write-Section "Dateiname"
$defaultName = New-TimeStampedName
Write-InfoLine ("Standardname: {0}" -f $defaultName)
$name = Read-Host "Dateiname, Enter für Standard"
if ([string]::IsNullOrWhiteSpace($name)) {
$name = $defaultName
}
if ($name.IndexOfAny([System.IO.Path]::GetInvalidFileNameChars()) -ge 0) {
throw "Ungültiger Dateiname."
}
return $name
}
function Get-LogFileName {
param([string]$TestFileName)
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($TestFileName)
return ("{0}.log.txt" -f $baseName)
}
function Safe-WriteLog {
param(
[string]$LogPath,
[string]$Message
)
if ([string]::IsNullOrWhiteSpace($LogPath)) {
return
}
try {
$line = "{0} | {1}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $Message
Add-Content -Path $LogPath -Value $line -ErrorAction Stop
}
catch {
}
}
function Initialize-Log {
param([string]$LogPath)
try {
if (-not (Test-Path $LogPath)) {
New-Item -Path $LogPath -ItemType File -Force | Out-Null
}
}
catch {
}
}
function Test-WritePermission {
param([string]$FolderPath)
$probeFile = Join-Path $FolderPath ("write_probe_{0}.tmp" -f ([guid]::NewGuid().ToString("N")))
try {
[System.IO.File]::WriteAllText($probeFile, "probe")
Remove-Item $probeFile -Force -ErrorAction Stop
}
catch {
throw "Schreibtest im Zielordner fehlgeschlagen: $($_.Exception.Message)"
}
}
function Run-MiniWriteTest {
param([string]$FolderPath)
Write-Section "Kurzer Schreibtest"
Write-InfoLine "Lege kleine Testdatei an und lösche sie wieder ..."
$probeFile = Join-Path $FolderPath ("mini_write_test_{0}.tmp" -f ([guid]::NewGuid().ToString("N")))
try {
$bytes = New-Object byte[] (64KB)
[System.IO.File]::WriteAllBytes($probeFile, $bytes)
Remove-Item $probeFile -Force -ErrorAction Stop
Write-Host "Schreibtest erfolgreich." -ForegroundColor Green
}
catch {
throw "Kurzer Schreibtest fehlgeschlagen: $($_.Exception.Message)"
}
}
function Get-SizeMode {
Write-Section "Schreibmenge"
Write-Host "[1] Maximal freier Platz, bis Laufwerk voll meldet" -ForegroundColor Green
Write-Host "[2] Definierte Grösse in GB" -ForegroundColor Green
return (Read-MenuChoice -Prompt "Bitte wählen" -AllowedValues @("1","2"))
}
function Get-FixedSizeBytes {
$sizeGB = Read-PositiveDouble -Prompt "Gewünschte Grösse in GB"
return [Int64]($sizeGB * 1GB)
}
function Get-LoopCount {
Write-Section "Durchläufe"
Write-Host "[1] 1 Durchlauf" -ForegroundColor Green
Write-Host "[2] 2 Durchläufe" -ForegroundColor Green
Write-Host "[3] 3 Durchläufe" -ForegroundColor Green
Write-Host "[4] Benutzerdefiniert" -ForegroundColor Green
Write-Host "[5] Unendlich bis CTRL+C" -ForegroundColor Green
$choice = Read-MenuChoice -Prompt "Bitte wählen" -AllowedValues @("1","2","3","4","5")
switch ($choice) {
"1" { return 1 }
"2" { return 2 }
"3" { return 3 }
"4" { return (Read-PositiveInt -Prompt "Anzahl Durchläufe") }
"5" { return -1 }
}
}
function Get-BlockSizeBytes {
Write-Section "Blockgrösse"
for ($i = 0; $i -lt $script:DefaultBlockSizesMB.Count; $i++) {
$mb = $script:DefaultBlockSizesMB[$i]
$suffix = if ($mb -eq 64) { " (Standard)" } else { "" }
Write-Host ("[{0}] {1} MB{2}" -f ($i + 1), $mb, $suffix) -ForegroundColor Green
}
Write-Host ("[{0}] Benutzerdefiniert" -f ($script:DefaultBlockSizesMB.Count + 1)) -ForegroundColor Green
$allowed = 1..($script:DefaultBlockSizesMB.Count + 1) | ForEach-Object { "$_" }
$choice = Read-MenuChoice -Prompt "Bitte wählen" -AllowedValues $allowed
if ([int]$choice -le $script:DefaultBlockSizesMB.Count) {
$mb = $script:DefaultBlockSizesMB[[int]$choice - 1]
return [Int64]($mb * 1MB)
}
$customMB = Read-PositiveInt -Prompt "Blockgrösse in MB"
return [Int64]($customMB * 1MB)
}
function Get-CurrentFreeBytes {
param([string]$DriveLetter)
$current = Get-CimInstance Win32_LogicalDisk -Filter ("DeviceID='{0}'" -f $DriveLetter)
if (-not $current) {
throw "Laufwerk $DriveLetter konnte nicht erneut ausgelesen werden."
}
return [Int64]$current.FreeSpace
}
function Start-Countdown {
param([int]$Seconds = 5)
Write-Section "Start"
for ($i = $Seconds; $i -ge 1; $i--) {
Write-Host ("Start in {0} ..." -f $i) -ForegroundColor Yellow
Start-Sleep -Seconds 1
}
}
function Handle-ExistingFile {
param([string]$FilePath)
if (-not (Test-Path $FilePath)) {
return
}
Write-Section "Vorhandene Testdatei gefunden"
Write-WarnLine ("Die Datei existiert bereits: {0}" -f $FilePath)
Write-Host "[1] Überschreiben" -ForegroundColor Green
Write-Host "[2] Löschen und neu starten" -ForegroundColor Green
Write-Host "[3] Abbrechen" -ForegroundColor Green
$choice = Read-MenuChoice -Prompt "Bitte wählen" -AllowedValues @("1","2","3")
switch ($choice) {
"1" { return }
"2" {
Remove-Item $FilePath -Force -ErrorAction Stop
return
}
"3" {
throw "Abgebrochen, weil bereits eine Datei mit demselben Namen existiert."
}
}
}
function Confirm-SystemDriveIfNeeded {
param([string]$DriveLetter)
if ($DriveLetter -ieq "C:") {
$confirm = Read-MenuChoice -Prompt "Du hast C: gewählt. Wirklich fortfahren? (j/n)" -AllowedValues @("j","J","n","N")
if ($confirm -notin @("j","J")) {
throw "Abgebrochen."
}
}
}
function Write-TestFileFixedSize {
param(
[string]$FilePath,
[Int64]$TargetBytes,
[Int64]$BlockSizeBytes,
[string]$LogPath
)
$freeBytesNow = Get-CurrentFreeBytes -DriveLetter ([System.IO.Path]::GetPathRoot($FilePath).TrimEnd('\'))
if ($TargetBytes -gt $freeBytesNow) {
throw ("Zu wenig freier Platz. Frei: {0}, benötigt: {1}" -f `
(Format-Bytes $freeBytesNow), (Format-Bytes $TargetBytes))
}
$buffer = New-Object byte[] $BlockSizeBytes
for ($i = 0; $i -lt $buffer.Length; $i++) {
$buffer[$i] = 0xAA
}
$written = 0L
$sw = [System.Diagnostics.Stopwatch]::StartNew()
Write-Host "Schreiben läuft ..." -ForegroundColor Magenta
Safe-WriteLog -LogPath $LogPath -Message ("Schreiben gestartet | Datei: {0} | Ziel: {1} | Block: {2}" -f `
$FilePath, (Format-Bytes $TargetBytes), (Format-Bytes $BlockSizeBytes))
$fs = $null
try {
$fs = [System.IO.File]::Open(
$FilePath,
[System.IO.FileMode]::Create,
[System.IO.FileAccess]::Write,
[System.IO.FileShare]::None
)
while ($written -lt $TargetBytes) {
$remaining = $TargetBytes - $written
$toWrite = if ($remaining -ge $BlockSizeBytes) { [int]$BlockSizeBytes } else { [int]$remaining }
$fs.Write($buffer, 0, $toWrite)
$written += $toWrite
$percent = [math]::Round(($written / $TargetBytes) * 100, 2)
$speedMBs = if ($sw.Elapsed.TotalSeconds -gt 0) {
[math]::Round(($written / 1MB) / $sw.Elapsed.TotalSeconds, 2)
} else {
0
}
Write-Progress -Activity "Schreiben läuft" `
-Status ("{0} / {1} | {2} MB/s" -f (Format-Bytes $written), (Format-Bytes $TargetBytes), $speedMBs) `
-PercentComplete $percent
}
$fs.Flush($true)
Write-Progress -Activity "Schreiben läuft" -Completed
}
finally {
if ($fs) { $fs.Dispose() }
}
$sw.Stop()
$seconds = [math]::Round($sw.Elapsed.TotalSeconds, 2)
$speed = if ($seconds -gt 0) { [math]::Round(($written / 1MB) / $seconds, 2) } else { 0 }
Safe-WriteLog -LogPath $LogPath -Message ("Schreiben abgeschlossen | Geschrieben: {0} | Dauer: {1}s | MB/s: {2}" -f `
(Format-Bytes $written), $seconds, $speed)
return [PSCustomObject]@{
WrittenBytes = $written
Seconds = $seconds
SpeedMBs = $speed
Mode = "Fixed"
}
}
function Write-TestFileMaxFill {
param(
[string]$FilePath,
[Int64]$BlockSizeBytes,
[string]$LogPath
)
$buffer = New-Object byte[] $BlockSizeBytes
for ($i = 0; $i -lt $buffer.Length; $i++) {
$buffer[$i] = 0xAA
}
$written = 0L
$sw = [System.Diagnostics.Stopwatch]::StartNew()
$fullReached = $false
$lastFreeBytes = 0L
Write-Host "Schreiben läuft ..." -ForegroundColor Magenta
Safe-WriteLog -LogPath $LogPath -Message ("Schreiben gestartet | Datei: {0} | Ziel: maximal frei | Block: {1}" -f `
$FilePath, (Format-Bytes $BlockSizeBytes))
$fs = $null
try {
$fs = [System.IO.File]::Open(
$FilePath,
[System.IO.FileMode]::Create,
[System.IO.FileAccess]::Write,
[System.IO.FileShare]::None
)
while ($true) {
try {
$fs.Write($buffer, 0, [int]$BlockSizeBytes)
$written += $BlockSizeBytes
$driveLetter = [System.IO.Path]::GetPathRoot($FilePath).TrimEnd('\')
$lastFreeBytes = Get-CurrentFreeBytes -DriveLetter $driveLetter
$speedMBs = if ($sw.Elapsed.TotalSeconds -gt 0) {
[math]::Round(($written / 1MB) / $sw.Elapsed.TotalSeconds, 2)
} else {
0
}
Write-Progress -Activity "Schreiben läuft" `
-Status ("Geschrieben: {0} | Verbleibend: {1} | {2} MB/s" -f `
(Format-Bytes $written), (Format-Bytes $lastFreeBytes), $speedMBs) `
-PercentComplete -1
}
catch [System.IO.IOException] {
$fullReached = $true
break
}
}
try {
$fs.Flush($true)
}
catch {
}
Write-Progress -Activity "Schreiben läuft" -Completed
}
finally {
if ($fs) { $fs.Dispose() }
}
$sw.Stop()
$seconds = [math]::Round($sw.Elapsed.TotalSeconds, 2)
$speed = if ($seconds -gt 0) { [math]::Round(($written / 1MB) / $seconds, 2) } else { 0 }
if (-not $fullReached) {
throw "Schreibvorgang wurde beendet, ohne dass ein voller Datenträger erkannt wurde."
}
Safe-WriteLog -LogPath $LogPath -Message ("Schreiben abgeschlossen | Maximalmodus | Geschrieben: {0} | Dauer: {1}s | MB/s: {2}" -f `
(Format-Bytes $written), $seconds, $speed)
return [PSCustomObject]@{
WrittenBytes = $written
Seconds = $seconds
SpeedMBs = $speed
Mode = "Max"
}
}
function Remove-TestFile {
param(
[string]$FilePath,
[string]$LogPath
)
if (Test-Path $FilePath) {
Write-Host "Löschen läuft ..." -ForegroundColor Magenta
Safe-WriteLog -LogPath $LogPath -Message ("Löschen gestartet | Datei: {0}" -f $FilePath)
$sw = [System.Diagnostics.Stopwatch]::StartNew()
Remove-Item $FilePath -Force -ErrorAction Stop
$sw.Stop()
$seconds = [math]::Round($sw.Elapsed.TotalSeconds, 2)
Safe-WriteLog -LogPath $LogPath -Message ("Löschen abgeschlossen | Dauer: {0}s" -f $seconds)
}
}
$targetFilePath = $null
$logPath = $null
try {
Clear-Host
Write-Section "Festplatten-Stresstest per Testdatei"
$selectedDrive = Select-Drive
Show-DriveWarnings -Drive $selectedDrive
$targetFolder = Get-TargetFolder -Drive $selectedDrive
Test-WritePermission -FolderPath $targetFolder
Run-MiniWriteTest -FolderPath $targetFolder
$testFileName = Get-TestFileName
$logFileName = Get-LogFileName -TestFileName $testFileName
$targetFilePath = Join-Path $targetFolder $testFileName
$logPath = Join-Path $targetFolder $logFileName
Initialize-Log -LogPath $logPath
Handle-ExistingFile -FilePath $targetFilePath
$sizeMode = Get-SizeMode
$fixedSizeBytes = 0L
if ($sizeMode -eq "2") {
$fixedSizeBytes = Get-FixedSizeBytes
}
$loopCount = Get-LoopCount
$blockSizeBytes = Get-BlockSizeBytes
Confirm-SystemDriveIfNeeded -DriveLetter $selectedDrive.DeviceID
$currentFreeBytes = Get-CurrentFreeBytes -DriveLetter $selectedDrive.DeviceID
$previewText = if ($sizeMode -eq "1") { "Maximal bis Laufwerk voll meldet" } else { (Format-Bytes $fixedSizeBytes) }
Write-Section "Zusammenfassung"
Write-Host ("Laufwerk: {0}" -f $selectedDrive.DeviceID) -ForegroundColor Green
Write-Host ("Zielordner: {0}" -f $targetFolder) -ForegroundColor Green
Write-Host ("Testdatei: {0}" -f $targetFilePath) -ForegroundColor Green
Write-Host ("Logdatei: {0}" -f $logPath) -ForegroundColor Green
Write-Host ("Freier Platz: {0}" -f (Format-Bytes $currentFreeBytes)) -ForegroundColor Green
Write-Host ("Modus: {0}" -f $(if ($sizeMode -eq "1") { "Maximal" } else { "Feste Grösse" })) -ForegroundColor Green
Write-Host ("Schreibmenge: {0}" -f $previewText) -ForegroundColor Green
Write-Host ("Blockgrösse: {0}" -f (Format-Bytes $blockSizeBytes)) -ForegroundColor Green
Write-Host ("Durchläufe: {0}" -f $(if ($loopCount -eq -1) { "Unendlich bis CTRL+C" } else { $loopCount })) -ForegroundColor Green
Safe-WriteLog -LogPath $logPath -Message "========================================"
Safe-WriteLog -LogPath $logPath -Message "Neuer Lauf gestartet"
Safe-WriteLog -LogPath $logPath -Message ("Laufwerk: {0}" -f $selectedDrive.DeviceID)
Safe-WriteLog -LogPath $logPath -Message ("Zielordner: {0}" -f $targetFolder)
Safe-WriteLog -LogPath $logPath -Message ("Testdatei: {0}" -f $targetFilePath)
Safe-WriteLog -LogPath $logPath -Message ("Freier Platz zu Beginn: {0}" -f (Format-Bytes $currentFreeBytes))
Safe-WriteLog -LogPath $logPath -Message ("Modus: {0}" -f $(if ($sizeMode -eq "1") { "Maximal" } else { "Feste Grösse" }))
Safe-WriteLog -LogPath $logPath -Message ("Blockgrösse: {0}" -f (Format-Bytes $blockSizeBytes))
Safe-WriteLog -LogPath $logPath -Message ("Durchläufe: {0}" -f $(if ($loopCount -eq -1) { "Unendlich" } else { $loopCount }))
$confirmStart = Read-MenuChoice -Prompt "Test starten? (j/n)" -AllowedValues @("j","J","n","N")
if ($confirmStart -notin @("j","J")) {
throw "Abgebrochen."
}
Start-Countdown -Seconds $script:DefaultCountdownSeconds
$iteration = 0
while ($true) {
$iteration++
Write-Section ("Durchlauf {0}" -f $iteration)
Safe-WriteLog -LogPath $logPath -Message ("Durchlauf {0} gestartet" -f $iteration)
$freeBytesNow = Get-CurrentFreeBytes -DriveLetter $selectedDrive.DeviceID
Write-Host ("Aktuell frei: {0}" -f (Format-Bytes $freeBytesNow)) -ForegroundColor DarkGray
Safe-WriteLog -LogPath $logPath -Message ("Durchlauf {0} | Freier Platz jetzt: {1}" -f $iteration, (Format-Bytes $freeBytesNow))
if ($sizeMode -eq "1") {
$result = Write-TestFileMaxFill -FilePath $targetFilePath -BlockSizeBytes $blockSizeBytes -LogPath $logPath
}
else {
Write-Host ("Schreibmenge: {0}" -f (Format-Bytes $fixedSizeBytes)) -ForegroundColor DarkGray
Safe-WriteLog -LogPath $logPath -Message ("Durchlauf {0} | Schreibmenge: {1}" -f $iteration, (Format-Bytes $fixedSizeBytes))
$result = Write-TestFileFixedSize `
-FilePath $targetFilePath `
-TargetBytes $fixedSizeBytes `
-BlockSizeBytes $blockSizeBytes `
-LogPath $logPath
}
Remove-TestFile -FilePath $targetFilePath -LogPath $logPath
Write-Host ("Durchlauf {0} abgeschlossen | Geschrieben: {1} | Dauer: {2} s | ca. {3} MB/s" -f `
$iteration, (Format-Bytes $result.WrittenBytes), $result.Seconds, $result.SpeedMBs) -ForegroundColor Green
Safe-WriteLog -LogPath $logPath -Message ("Durchlauf {0} abgeschlossen | Geschrieben: {1} | Dauer: {2}s | MB/s: {3}" -f `
$iteration, (Format-Bytes $result.WrittenBytes), $result.Seconds, $result.SpeedMBs)
if ($loopCount -ne -1 -and $iteration -ge $loopCount) {
break
}
}
Write-Section "Fertig"
Write-Host "Test abgeschlossen." -ForegroundColor Green
Safe-WriteLog -LogPath $logPath -Message "Test abgeschlossen"
}
catch {
$msg = $_.Exception.Message
Write-ErrorLine ""
Write-ErrorLine ("Fehler: {0}" -f $msg)
Safe-WriteLog -LogPath $logPath -Message ("Fehler: {0}" -f $msg)
}
finally {
try {
if ($targetFilePath -and (Test-Path $targetFilePath)) {
Write-WarnLine "Es wurde versucht, eine verbliebene Testdatei aufzuräumen ..."
Remove-Item $targetFilePath -Force -ErrorAction SilentlyContinue
Safe-WriteLog -LogPath $logPath -Message "Cleanup ausgeführt, verbliebene Testdatei entfernt sofern vorhanden"
}
}
catch {
}
Write-Host ""
Write-WarnLine "Hinweis: Bei Abbruch per CTRL+C wurde versucht, eine verbliebene Testdatei zu löschen."
if ($logPath) {
Write-Host ("Log: {0}" -f $logPath) -ForegroundColor DarkGray
}
}