From e2885e366cb49fd051945a517090c0bf938b8803 Mon Sep 17 00:00:00 2001 From: blance Date: Mon, 29 Jun 2026 19:33:03 -0500 Subject: [PATCH] Add run-all script to upload all practice folders from root --- run-all.bat | 3 ++ run-all.ps1 | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 run-all.bat create mode 100644 run-all.ps1 diff --git a/run-all.bat b/run-all.bat new file mode 100644 index 0000000..4140075 --- /dev/null +++ b/run-all.bat @@ -0,0 +1,3 @@ +@echo off +powershell.exe -ExecutionPolicy Bypass -File "%~dp0run-all.ps1" +pause diff --git a/run-all.ps1 b/run-all.ps1 new file mode 100644 index 0000000..1704583 --- /dev/null +++ b/run-all.ps1 @@ -0,0 +1,114 @@ +# Run FTP upload for every practice folder found under this root. +# Searches recursively for ftp-config.ini and uploads PDFs from each folder. + +$rootDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$configs = Get-ChildItem -Path $rootDir -Recurse -Filter "ftp-config.ini" + +if ($configs.Count -eq 0) { + Write-Host "No ftp-config.ini files found under $rootDir" -ForegroundColor Yellow + exit 0 +} + +Write-Host "" +Write-Host "Found $($configs.Count) practice folder(s)" -ForegroundColor Cyan +Write-Host ("=" * 50) + +$totalOk = 0 +$totalFail = 0 +$totalSkip = 0 + +foreach ($configFile in $configs) { + $folderDir = $configFile.DirectoryName + $folderName = Split-Path -Leaf $folderDir + + Write-Host "" + Write-Host "[ $folderName ]" -ForegroundColor Cyan + + # Parse config + $config = @{} + foreach ($line in Get-Content $configFile.FullName) { + if ($line -match '^\s*([^=;#\s]+)\s*=\s*(.+?)\s*$') { + $config[$matches[1]] = $matches[2] + } + } + + $ftpHost = $config["host"] + $ftpPort = if ($config["port"]) { [int]$config["port"] } else { 21 } + $username = $config["username"] + $password = $config["password"] + $remotePath = if ($config["remote_path"]) { $config["remote_path"].TrimEnd("/") } else { "/" } + $useTls = $config["tls"] -eq "true" + + if (-not $ftpHost -or -not $username -or -not $password) { + Write-Host " SKIPPED: ftp-config.ini missing required fields (host, username, password)" -ForegroundColor Yellow + $totalSkip++ + continue + } + + $archiveDir = Join-Path $folderDir "archive" + if (-not (Test-Path $archiveDir)) { + New-Item -ItemType Directory -Path $archiveDir | Out-Null + } + + $pdfs = Get-ChildItem -Path $folderDir -Filter "*.pdf" -File + + if ($pdfs.Count -eq 0) { + Write-Host " No PDFs to upload." -ForegroundColor Gray + $totalSkip++ + continue + } + + $ok = 0 + $fail = 0 + + foreach ($pdf in $pdfs) { + $remoteFile = "$remotePath/$($pdf.Name)" + $uri = "ftp://${ftpHost}:${ftpPort}${remoteFile}" + + Write-Host " $($pdf.Name) ..." -NoNewline + + try { + $req = [System.Net.FtpWebRequest]::Create($uri) + $req.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile + $req.Credentials = New-Object System.Net.NetworkCredential($username, $password) + $req.EnableSsl = $useTls + $req.UseBinary = $true + $req.UsePassive = $true + $req.KeepAlive = $false + + $bytes = [System.IO.File]::ReadAllBytes($pdf.FullName) + $req.ContentLength = $bytes.Length + $stream = $req.GetRequestStream() + $stream.Write($bytes, 0, $bytes.Length) + $stream.Close() + + $resp = $req.GetResponse() + $resp.Close() + + Move-Item -Path $pdf.FullName -Destination (Join-Path $archiveDir $pdf.Name) -Force + Write-Host " uploaded" -ForegroundColor Green + $ok++ + } + catch { + Write-Host " FAILED: $($_.Exception.Message)" -ForegroundColor Red + $fail++ + } + } + + $totalOk += $ok + $totalFail += $fail + + if ($fail -eq 0) { + Write-Host " $ok file(s) uploaded." -ForegroundColor Green + } else { + Write-Host " $ok uploaded, $fail failed." -ForegroundColor Yellow + } +} + +Write-Host "" +Write-Host ("=" * 50) +if ($totalFail -eq 0) { + Write-Host "All done: $totalOk file(s) uploaded across $($configs.Count) folder(s)." -ForegroundColor Green +} else { + Write-Host "Done: $totalOk uploaded, $totalFail failed, $totalSkip skipped." -ForegroundColor Yellow +}