Dataforth DOS: - TestDataDB: singleton DB connection fix (crash prevention), WAL mode, WinSW service config, backup script, uncaught exception handlers - Sync-FromNAS.ps1: Get-NASFileList temp file approach to avoid SSH stdout deadlock, *> $null output suppression, 8.3 filename filter for PUSH phase, backslash-escaped SCP paths, rename-to-.synced - import.js: INSERT OR REPLACE for re-tested devices - Full import run: 1,028,275 -> 1,632,793 records, indexes added - Deploy script for sync fixes to AD2 Client scripts (temp/): - BG Builders: Lesley account check, MFA phone update - Lonestar Electrical: Kyla/Russ Google Workspace setup, 2FA bypass - AD2 diagnostics and NAS connectivity tests PENDING: Investigate why newest test_date is Jan 19 despite daily tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
303 lines
12 KiB
PowerShell
303 lines
12 KiB
PowerShell
# 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
|