178 lines
7.1 KiB
PowerShell
178 lines
7.1 KiB
PowerShell
|
|
[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
|
||
|
|
|
||
|
|
# Scan for folders with YYYY-MM-DD format (e.g., 2023-12-15) instead of daily_*
|
||
|
|
$dailyDirs = Get-ChildItem -LiteralPath $root -Directory -Filter '????-??-??' | 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
|
||
|
|
}
|