Files
homelab-infra/ops/windows-reinstall/backup-delta-after-2026-05-07.ps1

119 lines
5.4 KiB
PowerShell

param(
[datetime]$Cutoff = "2026-05-07T15:30:00",
[string]$BackupRoot = "H:\Windows-Neuaufsetzen-Backup",
[string]$UserProfilePath = "C:\Users\michi"
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
function Invoke-RobocopyDelta {
param(
[string]$Source,
[string]$Destination,
[string]$LogName
)
if (-not (Test-Path $Source)) {
Write-Host "SKIP missing source: $Source"
return
}
New-Item -ItemType Directory -Force -Path $Destination | Out-Null
$LogPath = Join-Path $DeltaLogDir $LogName
Write-Host "DELTA COPY $Source"
Write-Host " -> $Destination"
robocopy $Source $Destination /E /COPY:DAT /DCOPY:DAT /R:2 /W:2 /XJ /MAXAGE:$CutoffString /TEE /LOG:$LogPath
$ExitCode = $LASTEXITCODE
if ($ExitCode -gt 7) {
throw "Robocopy failed with exit code $ExitCode for source: $Source"
}
}
if (-not (Test-Path $BackupRoot)) {
throw "BackupRoot does not exist: $BackupRoot"
}
if (-not (Test-Path $UserProfilePath)) {
throw "UserProfilePath does not exist: $UserProfilePath"
}
$DeltaRoot = Join-Path $BackupRoot "_Delta_2026-05-19"
$DeltaLogDir = Join-Path $DeltaRoot "00_Logs"
New-Item -ItemType Directory -Force -Path $DeltaLogDir | Out-Null
$CutoffString = $Cutoff.ToString("yyyyMMdd")
$Manifest = [ordered]@{
CreatedAt = (Get-Date).ToString("s")
Cutoff = $Cutoff.ToString("s")
CutoffNote = "Robocopy /MAXAGE uses date granularity, so files changed on or after the cutoff day are included."
RunningSystemDrive = $env:SystemDrive
RunningWinDir = $env:windir
BackupRoot = $BackupRoot
DeltaRoot = $DeltaRoot
}
$Manifest.GetEnumerator() |
ForEach-Object { "$($_.Key)=$($_.Value)" } |
Out-File (Join-Path $DeltaRoot "delta_manifest.txt") -Encoding UTF8
$Jobs = @(
@{ Source = Join-Path $UserProfilePath "Desktop"; Destination = Join-Path $DeltaRoot "01_Desktop"; Log = "delta_current_desktop.log" },
@{ Source = Join-Path $UserProfilePath "Documents"; Destination = Join-Path $DeltaRoot "02_Dokumente"; Log = "delta_current_documents.log" },
@{ Source = Join-Path $UserProfilePath "Pictures"; Destination = Join-Path $DeltaRoot "03_Bilder"; Log = "delta_current_pictures.log" },
@{ Source = Join-Path $UserProfilePath "Videos"; Destination = Join-Path $DeltaRoot "04_Videos"; Log = "delta_current_videos.log" },
@{ Source = Join-Path $UserProfilePath "Downloads"; Destination = Join-Path $DeltaRoot "05_Downloads"; Log = "delta_current_downloads.log" },
@{ Source = Join-Path $UserProfilePath ".ssh"; Destination = Join-Path $DeltaRoot "09_Programme_Settings_Lizenzen\ssh"; Log = "delta_current_ssh.log" },
@{ Source = Join-Path $UserProfilePath "AppData\Local\Subsembly"; Destination = Join-Path $DeltaRoot "09_Programme_Settings_Lizenzen\Subsembly_Local"; Log = "delta_subsembly_local.log" },
@{ Source = Join-Path $UserProfilePath "AppData\Local\Buhl"; Destination = Join-Path $DeltaRoot "09_Programme_Settings_Lizenzen\Buhl_Local"; Log = "delta_buhl_local.log" },
@{ Source = Join-Path $UserProfilePath "AppData\Local\Buhl Data Service GmbH"; Destination = Join-Path $DeltaRoot "09_Programme_Settings_Lizenzen\Buhl_Data_Service_Local"; Log = "delta_buhl_data_service_local.log" },
@{ Source = "C:\ProgramData\Buhl Data Service GmbH"; Destination = Join-Path $DeltaRoot "09_Programme_Settings_Lizenzen\Buhl_Data_Service_ProgramData"; Log = "delta_buhl_data_service_programdata.log" },
@{ Source = "G:\Gitea_Clone"; Destination = Join-Path $DeltaRoot "06_Projekte\Gitea_Clone"; Log = "delta_g_gitea_clone.log" },
@{ Source = "G:\open-webui"; Destination = Join-Path $DeltaRoot "09_Programme_Settings_Lizenzen\open-webui"; Log = "delta_g_open_webui.log" },
@{ Source = "G:\Treiber"; Destination = Join-Path $DeltaRoot "13_Treiber_Windows\G_Treiber"; Log = "delta_g_treiber.log" },
@{ Source = "F:\BMW Leasing"; Destination = Join-Path $DeltaRoot "07_Banking_Finanzen\BMW Leasing"; Log = "delta_f_bmw_leasing.log" },
@{ Source = "F:\Marina Handy 2025"; Destination = Join-Path $DeltaRoot "03_Bilder\Marina Handy 2025"; Log = "delta_f_marina_handy_2025.log" }
)
foreach ($Job in $Jobs) {
Invoke-RobocopyDelta -Source $Job.Source -Destination $Job.Destination -LogName $Job.Log
}
$ExplicitBankingDir = Join-Path $DeltaRoot "07_Banking_Finanzen\Banking4_Datentresor_explizit"
New-Item -ItemType Directory -Force -Path $ExplicitBankingDir | Out-Null
$BankingFiles = @(
(Join-Path $UserProfilePath "Documents\Mein Datentresor.sub"),
(Join-Path $UserProfilePath "Documents\.Mein Datentresor.sub.att")
)
foreach ($File in $BankingFiles) {
if (Test-Path $File) {
Copy-Item -LiteralPath $File -Destination (Join-Path $ExplicitBankingDir (Split-Path $File -Leaf)) -Force
}
}
$SummaryRoots = Get-ChildItem $DeltaRoot -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne "00_Logs" }
$Summary = foreach ($Root in $SummaryRoots) {
$Files = @(Get-ChildItem $Root.FullName -Recurse -Force -File -ErrorAction SilentlyContinue)
$Measure = $Files | Measure-Object Length -Sum
[pscustomobject]@{
Path = $Root.FullName
Files = $Files.Count
SizeGB = [math]::Round(($Measure.Sum / 1GB), 4)
Newest = ($Files | Sort-Object LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty LastWriteTime)
}
}
$Summary | Export-Csv (Join-Path $DeltaLogDir "delta_summary.csv") -NoTypeInformation -Encoding UTF8
Write-Host ""
Write-Host "Delta backup finished:"
Write-Host " $DeltaRoot"
Write-Host ""
Write-Host "Summary:"
$Summary | Format-Table -AutoSize