[CmdletBinding()] param( [switch]$DebugMode ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' function Get-YoungestTimestamp { param( [Parameter(Mandatory)] [string]$FolderPath ) $files = Get-ChildItem -LiteralPath $FolderPath -Recurse -File -ErrorAction SilentlyContinue | Where-Object { $_.FullName -notlike '*\_archive\*' } $young = $files | Sort-Object LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty LastWriteTime if (-not $young) { return [datetime]::Parse('1900-01-01') } return $young } try { $root = (Get-Location).ProviderPath $currentDir = Join-Path $root '_CURRENT' if (-not (Test-Path -LiteralPath $currentDir)) { New-Item -ItemType Directory -Path $currentDir -Force | Out-Null } $logFile = Join-Path $currentDir '_UpdateSequences.log' "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] === UpdateSequences (ps1) started in '$root' ===" | Add-Content -LiteralPath $logFile $dailyDirs = Get-ChildItem -LiteralPath $root -Directory -Filter 'daily_*' | Where-Object { $_.Name -ne '_archive' } $mapDaily = @{} $dailiesScanned = 0 foreach ($d in $dailyDirs) { $dailiesScanned++ $seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory | Where-Object { $_.Name -ne '_archive' }) if ($seqDirs.Count -eq 0) { $seqDirs = @($d) } foreach ($s in $seqDirs) { if (-not (Test-Path -LiteralPath $s.FullName)) { continue } $young = Get-YoungestTimestamp -FolderPath $s.FullName $filesCount = @(Get-ChildItem -LiteralPath $s.FullName -Recurse -File -ErrorAction SilentlyContinue | Where-Object { $_.FullName -notlike '*\_archive\*' }).Count $seqName = $s.Name $cand = [pscustomobject]@{ Seq = $seqName SrcFull = $s.FullName Young = $young FilesCount = $filesCount } if ($mapDaily.ContainsKey($seqName)) { if ($mapDaily[$seqName].Young -lt $young) { $mapDaily[$seqName] = $cand } } else { $mapDaily[$seqName] = $cand } } } $mapCurrent = @{} if (Test-Path -LiteralPath $currentDir) { foreach ($c in Get-ChildItem -LiteralPath $currentDir -Directory | Where-Object { $_.Name -ne '_archive' }) { $mapCurrent[$c.Name] = Get-YoungestTimestamp -FolderPath $c.FullName } } $lines = @() $lines += "[MAPCOUNT]|count=$($mapDaily.Count)" $total = 0 $toCopy = 0 foreach ($k in $mapDaily.Keys) { $total++ $d = $mapDaily[$k] $curYoung = if ($mapCurrent.ContainsKey($k)) { $mapCurrent[$k] } else { [datetime]::Parse('1900-01-01') } if ($d.Young -gt $curYoung) { $toCopy++ $lines += "[COPY]|$($d.SrcFull)|$($d.Seq)|files=$($d.FilesCount)|young=$($d.Young.ToString('s'))" } else { $lines += "[SKIP]|$($d.SrcFull)|$($d.Seq)|reason=notNewer|srcYoung=$($d.Young.ToString('s'))|curYoung=$($curYoung.ToString('s'))" } } $lines += "[META]|dailiesScanned=$dailiesScanned|sequencesTotal=$total|toCopy=$toCopy" # Print plan to console instead of writing to file Write-Host "=== UPDATE PLAN ===" -ForegroundColor Cyan foreach ($line in $lines) { if ($line -like '[COPY]*') { Write-Host $line -ForegroundColor Green } elseif ($line -like '[SKIP]*') { Write-Host $line -ForegroundColor Yellow } else { Write-Host $line -ForegroundColor White } } Write-Host "==================" -ForegroundColor Cyan $sequencesMirrored = 0 $mirrorFailures = 0 foreach ($line in $lines) { if ($line.StartsWith('[COPY]')) { $parts = $line -split '\|' $srcFull = $parts[1] $seqName = $parts[2] $dstAbs = Join-Path $currentDir $seqName if (-not (Test-Path -LiteralPath $dstAbs)) { New-Item -ItemType Directory -Path $dstAbs -Force | Out-Null } "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] Mirror: '$srcFull' -> '$dstAbs'" | Add-Content -LiteralPath $logFile $args = @( $srcFull, $dstAbs, '/MIR','/MT:8','/R:1','/W:1','/COPY:DAT','/DCOPY:DAT','/FFT','/NFL','/NDL','/NP','/NJH','/NJS','/XD','_archive' ) $null = & robocopy @args 2>&1 | Add-Content -LiteralPath $logFile $rc = $LASTEXITCODE if ($rc -lt 8) { $sequencesMirrored++ "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] OK rc=$rc" | Add-Content -LiteralPath $logFile } else { $mirrorFailures++ "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] ERROR rc=$rc" | Add-Content -LiteralPath $logFile } } } # Print summary report to console Write-Host "=== SUMMARY REPORT ===" -ForegroundColor Magenta Write-Host "Dailies scanned: $dailiesScanned" -ForegroundColor White Write-Host "Sequences found: $total" -ForegroundColor White Write-Host "Planned copies: $toCopy" -ForegroundColor Green Write-Host "Completed OK: $sequencesMirrored" -ForegroundColor Green Write-Host "Completed FAIL: $mirrorFailures" -ForegroundColor Red # Summarize skipped sequences $skippedLines = @() foreach ($line in $lines) { if ($line.StartsWith('[SKIP]')) { $skippedLines += $line } } if ($skippedLines.Count -gt 0) { Write-Host "`n=== SKIPPED SEQUENCES ===" -ForegroundColor Yellow $skippedByReason = @{} foreach ($skip in $skippedLines) { $parts = $skip -split '\|' $reason = $parts[3] $seqName = $parts[2] if (-not $skippedByReason.ContainsKey($reason)) { $skippedByReason[$reason] = @() } $skippedByReason[$reason] += $seqName } foreach ($reason in $skippedByReason.Keys) { $seqs = $skippedByReason[$reason] Write-Host "$reason ($($seqs.Count) sequences):" -ForegroundColor Yellow foreach ($seq in $seqs | Sort-Object) { Write-Host " - $seq" -ForegroundColor White } } Write-Host "========================" -ForegroundColor Yellow } Write-Host "=====================" -ForegroundColor Magenta "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] === UpdateSequences (ps1) completed (d=$dailiesScanned seq=$total ok=$sequencesMirrored fail=$mirrorFailures) ===" | Add-Content -LiteralPath $logFile Write-Host "@$logFile" exit 0 } catch { $root = (Get-Location).ProviderPath $currentDir = Join-Path $root '_CURRENT' if (-not (Test-Path -LiteralPath $currentDir)) { New-Item -ItemType Directory -Path $currentDir -Force | Out-Null } $planFile = Join-Path $currentDir '_UpdatePlan.txt' ($_.Exception | Out-String) | Set-Content -LiteralPath ($planFile + '.error.txt') -Encoding ASCII Write-Host "ERROR: $_" exit 1 }