diff --git a/UpdateSequences.ps1 b/UpdateSequences.ps1 new file mode 100644 index 0000000..1d5dac4 --- /dev/null +++ b/UpdateSequences.ps1 @@ -0,0 +1,178 @@ +[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 +} + +