# deploy-sync-fixes.ps1 # Deploys patched Sync-FromNAS.ps1 and import.js to AD2 (192.168.0.6) # # Fixes deployed: # 1. Sync-FromNAS.ps1 - PULL hang fix (temp file approach for large find output) # 2. Sync-FromNAS.ps1 - SCP quoting fix (handles spaces, parens, special chars) # 3. Sync-FromNAS.ps1 - Rename-OnNAS replaces Remove-FromNAS (.synced instead of delete) # 4. import.js - INSERT OR REPLACE instead of INSERT OR IGNORE (re-tests keep latest) # # Run from: Mike's workstation (where the patched files live) # Target: AD2 (192.168.0.6) as INTRANET\sysadmin param( [switch]$DryRun # Show what would be done without doing it ) # ============================================================================ # Configuration # ============================================================================ $AD2_IP = "192.168.0.6" $AD2_USER = "INTRANET\sysadmin" $AD2_PASSWORD = "Paper123!@#" $SSH = "C:\Windows\System32\OpenSSH\ssh.exe" $SCP = "C:\Windows\System32\OpenSSH\scp.exe" # Source files (local to this machine) $SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path $LOCAL_SYNC_SCRIPT = Join-Path $SCRIPT_DIR "Sync-FromNAS.ps1" $LOCAL_IMPORT_SCRIPT = Join-Path $SCRIPT_DIR "import.js" # Destination paths on AD2 $REMOTE_SYNC_PATH = "C:\Shares\test\scripts\Sync-FromNAS.ps1" $REMOTE_IMPORT_PATH = "C:\Shares\testdatadb\database\import.js" $REMOTE_SSH_DIR = "C:\Shares\test\scripts\.ssh" $DATE_SUFFIX = Get-Date -Format "yyyyMMdd" # ============================================================================ # Functions # ============================================================================ function Write-Status { param( [string]$Marker, [string]$Message ) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" Write-Host "$timestamp [$Marker] $Message" } function Invoke-AD2Command { param([string]$Command) $result = & $SSH -o StrictHostKeyChecking=accept-new -o ConnectTimeout=10 "${AD2_USER}@${AD2_IP}" $Command 2>&1 return $result } function Copy-ToAD2 { param( [string]$LocalPath, [string]$RemotePath ) # SCP to AD2 - quote remote path for Windows paths with backslashes $result = & $SCP -O -o StrictHostKeyChecking=accept-new "$LocalPath" "${AD2_USER}@${AD2_IP}:`"${RemotePath}`"" 2>&1 if ($LASTEXITCODE -ne 0) { $errorMsg = $result | Out-String Write-Status "ERROR" "SCP failed (exit $LASTEXITCODE): $errorMsg" return $false } return $true } # ============================================================================ # Pre-flight Checks # ============================================================================ Write-Host "" Write-Host "============================================" Write-Host " Dataforth Sync Fixes - Deployment Script" Write-Host "============================================" Write-Host "" if ($DryRun) { Write-Status "INFO" "DRY RUN - no changes will be made" Write-Host "" } # Verify source files exist Write-Status "INFO" "Checking source files..." if (-not (Test-Path $LOCAL_SYNC_SCRIPT)) { Write-Status "ERROR" "Source file not found: $LOCAL_SYNC_SCRIPT" exit 1 } Write-Status "OK" "Found: $LOCAL_SYNC_SCRIPT" if (-not (Test-Path $LOCAL_IMPORT_SCRIPT)) { Write-Status "ERROR" "Source file not found: $LOCAL_IMPORT_SCRIPT" exit 1 } Write-Status "OK" "Found: $LOCAL_IMPORT_SCRIPT" # Verify AD2 is reachable Write-Status "INFO" "Testing connectivity to AD2 ($AD2_IP)..." $pingResult = Test-Connection -ComputerName $AD2_IP -Count 1 -Quiet if (-not $pingResult) { Write-Status "ERROR" "Cannot reach AD2 at $AD2_IP" exit 1 } Write-Status "OK" "AD2 is reachable" # Test SSH connection Write-Status "INFO" "Testing SSH connection..." $sshTest = Invoke-AD2Command "echo CONNECTION_OK" $sshTestStr = $sshTest | Out-String if ($sshTestStr -notmatch "CONNECTION_OK") { Write-Status "ERROR" "SSH connection failed: $sshTestStr" exit 1 } Write-Status "OK" "SSH connection established" # ============================================================================ # Step 1: Create backups on AD2 # ============================================================================ Write-Host "" Write-Status "INFO" "--- Step 1: Creating backups on AD2 ---" if ($DryRun) { Write-Status "INFO" "[DRY RUN] Would backup $REMOTE_SYNC_PATH -> ${REMOTE_SYNC_PATH}.bak-${DATE_SUFFIX}" Write-Status "INFO" "[DRY RUN] Would backup $REMOTE_IMPORT_PATH -> ${REMOTE_IMPORT_PATH}.bak-${DATE_SUFFIX}" } else { # Backup Sync-FromNAS.ps1 $backupCmd1 = "copy `"$REMOTE_SYNC_PATH`" `"${REMOTE_SYNC_PATH}.bak-${DATE_SUFFIX}`"" $backupResult1 = Invoke-AD2Command "cmd /c $backupCmd1" if ($LASTEXITCODE -eq 0) { Write-Status "OK" "Backed up Sync-FromNAS.ps1 -> .bak-${DATE_SUFFIX}" } else { Write-Status "WARNING" "Backup of Sync-FromNAS.ps1 may have failed (file might not exist yet): $($backupResult1 | Out-String)" } # Backup import.js $backupCmd2 = "copy `"$REMOTE_IMPORT_PATH`" `"${REMOTE_IMPORT_PATH}.bak-${DATE_SUFFIX}`"" $backupResult2 = Invoke-AD2Command "cmd /c $backupCmd2" if ($LASTEXITCODE -eq 0) { Write-Status "OK" "Backed up import.js -> .bak-${DATE_SUFFIX}" } else { Write-Status "WARNING" "Backup of import.js may have failed (file might not exist yet): $($backupResult2 | Out-String)" } } # ============================================================================ # Step 2: Create .ssh directory on AD2 if missing # ============================================================================ Write-Host "" Write-Status "INFO" "--- Step 2: Ensuring .ssh directory exists ---" if ($DryRun) { Write-Status "INFO" "[DRY RUN] Would create $REMOTE_SSH_DIR if missing" } else { $mkdirCmd = "cmd /c if not exist `"$REMOTE_SSH_DIR`" mkdir `"$REMOTE_SSH_DIR`"" Invoke-AD2Command $mkdirCmd | Out-Null Write-Status "OK" "Ensured .ssh directory exists: $REMOTE_SSH_DIR" # Create empty known_hosts if it does not exist $knownHostsPath = "$REMOTE_SSH_DIR\known_hosts" $touchCmd = "cmd /c if not exist `"$knownHostsPath`" type nul > `"$knownHostsPath`"" Invoke-AD2Command $touchCmd | Out-Null Write-Status "OK" "Ensured known_hosts file exists: $knownHostsPath" } # ============================================================================ # Step 3: Deploy patched files # ============================================================================ Write-Host "" Write-Status "INFO" "--- Step 3: Deploying patched files ---" if ($DryRun) { Write-Status "INFO" "[DRY RUN] Would SCP $LOCAL_SYNC_SCRIPT -> ${AD2_IP}:${REMOTE_SYNC_PATH}" Write-Status "INFO" "[DRY RUN] Would SCP $LOCAL_IMPORT_SCRIPT -> ${AD2_IP}:${REMOTE_IMPORT_PATH}" } else { # Deploy Sync-FromNAS.ps1 Write-Status "INFO" "Deploying Sync-FromNAS.ps1..." $success1 = Copy-ToAD2 -LocalPath $LOCAL_SYNC_SCRIPT -RemotePath $REMOTE_SYNC_PATH if ($success1) { Write-Status "OK" "Deployed Sync-FromNAS.ps1" } else { Write-Status "ERROR" "Failed to deploy Sync-FromNAS.ps1" exit 1 } # Deploy import.js Write-Status "INFO" "Deploying import.js..." $success2 = Copy-ToAD2 -LocalPath $LOCAL_IMPORT_SCRIPT -RemotePath $REMOTE_IMPORT_PATH if ($success2) { Write-Status "OK" "Deployed import.js" } else { Write-Status "ERROR" "Failed to deploy import.js" exit 1 } } # ============================================================================ # Step 4: Verify deployment # ============================================================================ Write-Host "" Write-Status "INFO" "--- Step 4: Verifying deployment ---" if ($DryRun) { Write-Status "INFO" "[DRY RUN] Would verify files exist on AD2" } else { # Check Sync-FromNAS.ps1 exists and has content $verifyCmd1 = "cmd /c if exist `"$REMOTE_SYNC_PATH`" (echo FILE_EXISTS) else (echo FILE_MISSING)" $verify1 = Invoke-AD2Command $verifyCmd1 | Out-String if ($verify1 -match "FILE_EXISTS") { Write-Status "OK" "Verified: Sync-FromNAS.ps1 exists on AD2" } else { Write-Status "ERROR" "Verification failed: Sync-FromNAS.ps1 not found on AD2" exit 1 } # Check import.js exists $verifyCmd2 = "cmd /c if exist `"$REMOTE_IMPORT_PATH`" (echo FILE_EXISTS) else (echo FILE_MISSING)" $verify2 = Invoke-AD2Command $verifyCmd2 | Out-String if ($verify2 -match "FILE_EXISTS") { Write-Status "OK" "Verified: import.js exists on AD2" } else { Write-Status "ERROR" "Verification failed: import.js not found on AD2" exit 1 } } # ============================================================================ # Step 5: Quick dry-run test of the sync script # ============================================================================ Write-Host "" Write-Status "INFO" "--- Step 5: Running dry-run test of sync script ---" if ($DryRun) { Write-Status "INFO" "[DRY RUN] Would run: powershell -ExecutionPolicy Bypass -File $REMOTE_SYNC_PATH -DryRun" } else { Write-Status "INFO" "Executing sync script in dry-run mode on AD2..." $testCmd = "powershell -ExecutionPolicy Bypass -File `"$REMOTE_SYNC_PATH`" -DryRun -Verbose" $testResult = Invoke-AD2Command $testCmd $testOutput = $testResult | Out-String # Check if the script ran without critical errors if ($LASTEXITCODE -eq 0) { Write-Status "OK" "Sync script dry-run completed successfully" if ($testOutput.Trim().Length -gt 0) { Write-Host "" Write-Host " --- Dry-run output ---" foreach ($line in ($testResult | Select-Object -First 20)) { Write-Host " $line" } $totalLines = ($testResult | Measure-Object).Count if ($totalLines -gt 20) { Write-Host " ... ($($totalLines - 20) more lines)" } Write-Host " --- End dry-run output ---" } } else { Write-Status "WARNING" "Sync script dry-run exited with code $LASTEXITCODE" Write-Status "INFO" "This may be expected if NAS is unreachable from AD2 during test" if ($testOutput.Trim().Length -gt 0) { Write-Host "" Write-Host " --- Dry-run output ---" foreach ($line in ($testResult | Select-Object -First 10)) { Write-Host " $line" } Write-Host " --- End dry-run output ---" } } } # ============================================================================ # Summary # ============================================================================ Write-Host "" Write-Host "============================================" Write-Host " Deployment Summary" Write-Host "============================================" Write-Host "" if ($DryRun) { Write-Status "INFO" "DRY RUN complete - no changes were made" } else { Write-Status "OK" "Sync-FromNAS.ps1 deployed to AD2 (backup: .bak-${DATE_SUFFIX})" Write-Status "OK" "import.js deployed to AD2 (backup: .bak-${DATE_SUFFIX})" Write-Status "OK" ".ssh directory and known_hosts verified" Write-Status "OK" "Dry-run test executed" Write-Host "" Write-Status "INFO" "Fixes applied:" Write-Host " 1. PULL hang fix: find output written to temp file, pulled via SCP" Write-Host " 2. SCP quoting fix: remote paths quoted to handle special characters" Write-Host " 3. Rename-OnNAS: files renamed to .synced instead of deleted" Write-Host " 4. INSERT OR REPLACE: re-tested devices keep latest result" Write-Host "" Write-Status "INFO" "Next sync cycle will use the patched scripts automatically" } Write-Host "" exit 0