forked from Goko/JingTian-Rclone
- Add -NonInteractive switch parameter - Auto-accept detected BenjaminTeam folder in non-interactive mode - Fix SSH test to use StrictHostKeyChecking=no and ConnectTimeout - Add try/catch for better error handling during SSH test
390 lines
13 KiB
PowerShell
390 lines
13 KiB
PowerShell
#Requires -RunAsAdministrator
|
|
<#
|
|
.SYNOPSIS
|
|
JingTian rclone Client Setup Script for Windows
|
|
|
|
.DESCRIPTION
|
|
This script sets up rclone sync on a Windows client machine to sync
|
|
the BenjaminTeam folder with the remote Ubuntu server.
|
|
|
|
.PARAMETER ServerHost
|
|
The IP address or hostname of the Ubuntu sync server.
|
|
Default: 20.240.140.78
|
|
|
|
.PARAMETER ServerUser
|
|
The SSH username on the Ubuntu server.
|
|
Default: rclone-sync
|
|
|
|
.PARAMETER ServerPath
|
|
The remote path on the Ubuntu server.
|
|
Default: /data/jingtian/BenjaminTeam
|
|
|
|
.PARAMETER LocalPath
|
|
The local BenjaminTeam folder path. If not specified, the script will
|
|
attempt to auto-detect or prompt the user.
|
|
|
|
.PARAMETER SyncInterval
|
|
Sync interval in minutes for the scheduled task.
|
|
Default: 5
|
|
|
|
.PARAMETER NonInteractive
|
|
Run without prompts. Auto-accepts detected BenjaminTeam folder.
|
|
Use this when running from scripts or scheduled tasks.
|
|
|
|
.EXAMPLE
|
|
.\setup.ps1
|
|
|
|
.EXAMPLE
|
|
.\setup.ps1 -LocalPath "D:\Work\BenjaminTeam" -SyncInterval 10
|
|
#>
|
|
|
|
param(
|
|
[string]$ServerHost = "20.240.140.78",
|
|
[string]$ServerUser = "rclone-sync",
|
|
[string]$ServerPath = "/data/jingtian/BenjaminTeam",
|
|
[string]$LocalPath = "",
|
|
[int]$SyncInterval = 5,
|
|
[switch]$NonInteractive
|
|
)
|
|
|
|
# Configuration
|
|
$ErrorActionPreference = "Stop"
|
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$RcloneKeySource = Join-Path $ScriptDir "rclone-key"
|
|
$RcloneKeyDest = "$env:USERPROFILE\.ssh\jingtian_rclone"
|
|
$RcloneConfigDir = "$env:APPDATA\rclone"
|
|
$RcloneConfigFile = "$RcloneConfigDir\rclone.conf"
|
|
$SyncScriptPath = Join-Path $ScriptDir "sync.ps1"
|
|
$LogDir = "$env:LOCALAPPDATA\JingTian\logs"
|
|
|
|
# Styling
|
|
function Write-Header {
|
|
param([string]$Text)
|
|
Write-Host ""
|
|
Write-Host "===========================================" -ForegroundColor Cyan
|
|
Write-Host $Text -ForegroundColor Cyan
|
|
Write-Host "===========================================" -ForegroundColor Cyan
|
|
}
|
|
|
|
function Write-Step {
|
|
param([string]$Step, [string]$Text)
|
|
Write-Host ""
|
|
Write-Host "[$Step] $Text" -ForegroundColor Yellow
|
|
}
|
|
|
|
function Write-Success {
|
|
param([string]$Text)
|
|
Write-Host " [OK] $Text" -ForegroundColor Green
|
|
}
|
|
|
|
function Write-Info {
|
|
param([string]$Text)
|
|
Write-Host " $Text" -ForegroundColor Gray
|
|
}
|
|
|
|
function Write-ErrorMsg {
|
|
param([string]$Text)
|
|
Write-Host " [ERROR] $Text" -ForegroundColor Red
|
|
}
|
|
|
|
# ============================================================
|
|
# MAIN SCRIPT
|
|
# ============================================================
|
|
|
|
Write-Header "JingTian rclone Client Setup"
|
|
|
|
Write-Host ""
|
|
Write-Host "Server: $ServerHost" -ForegroundColor White
|
|
Write-Host "User: $ServerUser" -ForegroundColor White
|
|
Write-Host "Remote: $ServerPath" -ForegroundColor White
|
|
|
|
# ------------------------------------------------------------
|
|
# Step 1: Check/Install Git
|
|
# ------------------------------------------------------------
|
|
Write-Step "1/7" "Checking Git installation..."
|
|
|
|
$gitPath = "C:\Program Files\Git\bin\git.exe"
|
|
if (Test-Path $gitPath) {
|
|
$gitVersion = & $gitPath --version
|
|
Write-Success "Git already installed: $gitVersion"
|
|
} else {
|
|
Write-Info "Git not found. Installing..."
|
|
|
|
$gitInstaller = "$env:TEMP\git-installer.exe"
|
|
$gitUrl = "https://github.com/git-for-windows/git/releases/download/v2.43.0.windows.1/Git-2.43.0-64-bit.exe"
|
|
|
|
Write-Info "Downloading Git installer..."
|
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
Invoke-WebRequest -Uri $gitUrl -OutFile $gitInstaller
|
|
|
|
Write-Info "Installing Git (this may take a few minutes)..."
|
|
Start-Process -FilePath $gitInstaller -ArgumentList '/VERYSILENT /NORESTART /NOCANCEL /SP- /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /COMPONENTS=icons,ext\reg\shellhere,assoc,assoc_sh' -Wait
|
|
|
|
if (Test-Path $gitPath) {
|
|
Write-Success "Git installed successfully"
|
|
} else {
|
|
Write-ErrorMsg "Git installation failed"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
# ------------------------------------------------------------
|
|
# Step 2: Check/Install rclone
|
|
# ------------------------------------------------------------
|
|
Write-Step "2/7" "Checking rclone installation..."
|
|
|
|
$rclonePath = "$env:LOCALAPPDATA\rclone\rclone.exe"
|
|
$rclonePathAlt = "C:\rclone\rclone.exe"
|
|
|
|
if (Test-Path $rclonePath) {
|
|
$rcloneVersion = & $rclonePath version | Select-Object -First 1
|
|
Write-Success "rclone already installed: $rcloneVersion"
|
|
} elseif (Test-Path $rclonePathAlt) {
|
|
$rclonePath = $rclonePathAlt
|
|
$rcloneVersion = & $rclonePath version | Select-Object -First 1
|
|
Write-Success "rclone already installed: $rcloneVersion"
|
|
} else {
|
|
Write-Info "rclone not found. Installing..."
|
|
|
|
$rcloneZip = "$env:TEMP\rclone.zip"
|
|
$rcloneExtract = "$env:TEMP\rclone-extract"
|
|
$rcloneInstallDir = "$env:LOCALAPPDATA\rclone"
|
|
$rcloneUrl = "https://downloads.rclone.org/rclone-current-windows-amd64.zip"
|
|
|
|
Write-Info "Downloading rclone..."
|
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
Invoke-WebRequest -Uri $rcloneUrl -OutFile $rcloneZip
|
|
|
|
Write-Info "Extracting rclone..."
|
|
if (Test-Path $rcloneExtract) { Remove-Item -Recurse -Force $rcloneExtract }
|
|
Expand-Archive -Path $rcloneZip -DestinationPath $rcloneExtract
|
|
|
|
# Find the extracted folder (it has version in the name)
|
|
$extractedFolder = Get-ChildItem -Path $rcloneExtract -Directory | Select-Object -First 1
|
|
|
|
# Create install directory and copy rclone
|
|
if (-not (Test-Path $rcloneInstallDir)) {
|
|
New-Item -ItemType Directory -Path $rcloneInstallDir -Force | Out-Null
|
|
}
|
|
Copy-Item -Path "$($extractedFolder.FullName)\rclone.exe" -Destination $rclonePath -Force
|
|
|
|
# Clean up
|
|
Remove-Item -Recurse -Force $rcloneZip, $rcloneExtract
|
|
|
|
if (Test-Path $rclonePath) {
|
|
Write-Success "rclone installed to $rclonePath"
|
|
} else {
|
|
Write-ErrorMsg "rclone installation failed"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
# ------------------------------------------------------------
|
|
# Step 3: Detect/Confirm BenjaminTeam folder
|
|
# ------------------------------------------------------------
|
|
Write-Step "3/7" "Locating BenjaminTeam folder..."
|
|
|
|
if ($LocalPath -and (Test-Path $LocalPath)) {
|
|
Write-Success "Using specified path: $LocalPath"
|
|
} else {
|
|
# Common locations to search
|
|
$searchPaths = @(
|
|
"$env:USERPROFILE\Documents\BenjaminTeam",
|
|
"$env:USERPROFILE\Documents\Benjamin Team",
|
|
"D:\BenjaminTeam",
|
|
"D:\Benjamin Team",
|
|
"C:\BenjaminTeam",
|
|
"C:\Benjamin Team"
|
|
)
|
|
|
|
$foundPath = $null
|
|
foreach ($path in $searchPaths) {
|
|
if (Test-Path $path) {
|
|
$foundPath = $path
|
|
break
|
|
}
|
|
}
|
|
|
|
if ($foundPath) {
|
|
Write-Info "Found BenjaminTeam folder at: $foundPath"
|
|
if ($NonInteractive) {
|
|
# Auto-accept in non-interactive mode
|
|
$LocalPath = $foundPath
|
|
} else {
|
|
$confirm = Read-Host " Use this path? (Y/n)"
|
|
if ($confirm -eq "" -or $confirm -match "^[Yy]") {
|
|
$LocalPath = $foundPath
|
|
}
|
|
}
|
|
}
|
|
|
|
if (-not $LocalPath -or -not (Test-Path $LocalPath)) {
|
|
if ($NonInteractive) {
|
|
Write-ErrorMsg "Could not auto-detect BenjaminTeam folder. Use -LocalPath parameter."
|
|
exit 1
|
|
}
|
|
Write-Info "Could not auto-detect BenjaminTeam folder."
|
|
$LocalPath = Read-Host " Enter the full path to your BenjaminTeam folder"
|
|
|
|
if (-not (Test-Path $LocalPath)) {
|
|
Write-ErrorMsg "Path does not exist: $LocalPath"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
Write-Success "Using path: $LocalPath"
|
|
}
|
|
|
|
# Ensure _LLM_Sync folder exists
|
|
$llmSyncPath = Join-Path $LocalPath "_LLM_Sync"
|
|
if (-not (Test-Path $llmSyncPath)) {
|
|
New-Item -ItemType Directory -Path $llmSyncPath -Force | Out-Null
|
|
Write-Info "Created _LLM_Sync folder"
|
|
}
|
|
|
|
# ------------------------------------------------------------
|
|
# Step 4: Setup SSH key
|
|
# ------------------------------------------------------------
|
|
Write-Step "4/7" "Setting up SSH key..."
|
|
|
|
# Create .ssh directory if it doesn't exist
|
|
$sshDir = "$env:USERPROFILE\.ssh"
|
|
if (-not (Test-Path $sshDir)) {
|
|
New-Item -ItemType Directory -Path $sshDir -Force | Out-Null
|
|
}
|
|
|
|
# Copy the SSH key
|
|
if (-not (Test-Path $RcloneKeySource)) {
|
|
Write-ErrorMsg "SSH key not found at: $RcloneKeySource"
|
|
Write-Info "Make sure the rclone-key file is in the same directory as this script."
|
|
exit 1
|
|
}
|
|
|
|
Copy-Item -Path $RcloneKeySource -Destination $RcloneKeyDest -Force
|
|
Write-Success "SSH key copied to $RcloneKeyDest"
|
|
|
|
# Test SSH connection (fully non-interactive)
|
|
Write-Info "Testing SSH connection to $ServerHost..."
|
|
$sshArgs = @(
|
|
"-o", "StrictHostKeyChecking=no",
|
|
"-o", "BatchMode=yes",
|
|
"-o", "ConnectTimeout=10",
|
|
"-o", "UserKnownHostsFile=$env:USERPROFILE\.ssh\known_hosts",
|
|
"-i", $RcloneKeyDest,
|
|
"$ServerUser@$ServerHost",
|
|
"echo 'SSH_OK'"
|
|
)
|
|
|
|
try {
|
|
$sshTest = & ssh @sshArgs 2>&1
|
|
if ($sshTest -match "SSH_OK") {
|
|
Write-Success "SSH connection successful"
|
|
} else {
|
|
Write-ErrorMsg "SSH connection failed: $sshTest"
|
|
Write-Info "Please check the server is running and the key is correct."
|
|
exit 1
|
|
}
|
|
} catch {
|
|
Write-ErrorMsg "SSH test error: $_"
|
|
exit 1
|
|
}
|
|
|
|
# ------------------------------------------------------------
|
|
# Step 5: Configure rclone
|
|
# ------------------------------------------------------------
|
|
Write-Step "5/7" "Configuring rclone..."
|
|
|
|
# Create rclone config directory
|
|
if (-not (Test-Path $RcloneConfigDir)) {
|
|
New-Item -ItemType Directory -Path $RcloneConfigDir -Force | Out-Null
|
|
}
|
|
|
|
# Generate rclone config
|
|
$rcloneConfig = @"
|
|
[jingtian-server]
|
|
type = sftp
|
|
host = $ServerHost
|
|
user = $ServerUser
|
|
key_file = $RcloneKeyDest
|
|
shell_type = unix
|
|
"@
|
|
|
|
# Write config file
|
|
Set-Content -Path $RcloneConfigFile -Value $rcloneConfig -Encoding ASCII
|
|
Write-Success "rclone config written to $RcloneConfigFile"
|
|
|
|
# Test rclone connection
|
|
Write-Info "Testing rclone connection..."
|
|
$rcloneTest = & $rclonePath lsd "jingtian-server:$ServerPath" 2>&1
|
|
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Success "rclone connection successful"
|
|
Write-Info "Remote folders:"
|
|
$rcloneTest | ForEach-Object { Write-Info " $_" }
|
|
} else {
|
|
Write-ErrorMsg "rclone connection failed: $rcloneTest"
|
|
exit 1
|
|
}
|
|
|
|
# ------------------------------------------------------------
|
|
# Step 6: Create log directory
|
|
# ------------------------------------------------------------
|
|
Write-Step "6/7" "Setting up logging..."
|
|
|
|
if (-not (Test-Path $LogDir)) {
|
|
New-Item -ItemType Directory -Path $LogDir -Force | Out-Null
|
|
}
|
|
Write-Success "Log directory: $LogDir"
|
|
|
|
# ------------------------------------------------------------
|
|
# Step 7: Create Scheduled Task
|
|
# ------------------------------------------------------------
|
|
Write-Step "7/7" "Creating scheduled sync task..."
|
|
|
|
$taskName = "JingTian-Sync"
|
|
$taskDescription = "Syncs BenjaminTeam folder with remote server every $SyncInterval minutes"
|
|
|
|
# Remove existing task if it exists
|
|
$existingTask = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
|
|
if ($existingTask) {
|
|
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
|
|
Write-Info "Removed existing scheduled task"
|
|
}
|
|
|
|
# Create the scheduled task
|
|
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ExecutionPolicy Bypass -WindowStyle Hidden -File `"$SyncScriptPath`" -LocalPath `"$LocalPath`" -RclonePath `"$rclonePath`" -LogDir `"$LogDir`""
|
|
|
|
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes $SyncInterval) -RepetitionDuration (New-TimeSpan -Days 9999)
|
|
|
|
$principal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType Interactive -RunLevel Highest
|
|
|
|
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Hours 1)
|
|
|
|
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Description $taskDescription | Out-Null
|
|
|
|
Write-Success "Scheduled task created: $taskName"
|
|
Write-Info "Sync will run every $SyncInterval minutes"
|
|
|
|
# ------------------------------------------------------------
|
|
# Summary
|
|
# ------------------------------------------------------------
|
|
Write-Header "Setup Complete!"
|
|
|
|
Write-Host ""
|
|
Write-Host "Configuration Summary:" -ForegroundColor White
|
|
Write-Host " Local Path: $LocalPath" -ForegroundColor Gray
|
|
Write-Host " Remote: $ServerUser@$ServerHost`:$ServerPath" -ForegroundColor Gray
|
|
Write-Host " Sync Interval: Every $SyncInterval minutes" -ForegroundColor Gray
|
|
Write-Host " Log Directory: $LogDir" -ForegroundColor Gray
|
|
Write-Host ""
|
|
Write-Host "Sync Behavior:" -ForegroundColor White
|
|
Write-Host " - Main folders: One-way sync (Windows -> Server)" -ForegroundColor Gray
|
|
Write-Host " - _LLM_Sync: Bidirectional sync" -ForegroundColor Gray
|
|
Write-Host ""
|
|
Write-Host "To manually trigger a sync, run:" -ForegroundColor White
|
|
Write-Host " .\sync.ps1" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
Write-Host "To check sync logs:" -ForegroundColor White
|
|
Write-Host " Get-Content `"$LogDir\sync.log`" -Tail 50" -ForegroundColor Cyan
|
|
Write-Host ""
|