Backup-AdHoc/install-AdHoc-Backup.ps1

440 lines
15 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<#
install-AdHoc-Backup.ps1
Menù di installazione / pianificazione / configurazione per AdHoc-Backup.ps1
#>
# ==========================
# CONFIGURAZIONE INIZIALE
# ==========================
$InstallRoot = "C:\polo\script"
$BackupScriptName = "AdHoc-Backup.ps1"
$ConfigFileName = "backup.conf"
# link dal tuo Gitea
$DownloadMap = @{
"AdHoc-Backup.ps1" = "https://gitea.poloinformatico.it/Mattia/Backup-AdHoc/raw/branch/main/AdHoc-Backup.ps1"
"backup.conf" = "https://gitea.poloinformatico.it/Mattia/Backup-AdHoc/raw/branch/main/backup.conf"
}
# URL degli strumenti come nello script di backup
$SevenZipPortableUrl = 'https://www.7-zip.org/a/7zr.exe'
$RcloneZipUrl = 'https://downloads.rclone.org/rclone-current-windows-amd64.zip'
# ==========================
# FUNZIONI DI SUPPORTO
# ==========================
function Ensure-Folder {
param([string]$Path)
if (-not (Test-Path $Path)) {
Write-Host "Creo la cartella $Path ..." -ForegroundColor Yellow
New-Item -ItemType Directory -Path $Path -Force | Out-Null
}
}
function Download-File {
param(
[string]$Url,
[string]$Destination
)
try {
Write-Host "Scarico $Url -> $Destination"
Invoke-WebRequest -Uri $Url -OutFile $Destination -UseBasicParsing
}
catch {
Write-Warning "Impossibile scaricare $Url. Errore: $($_.Exception.Message)"
}
}
function Read-YesNo {
param(
[string]$Message,
[bool]$Default = $true
)
if ($Default) {
$msg = "$Message [S/n]"
} else {
$msg = "$Message [s/N]"
}
$ans = Read-Host $msg
if ([string]::IsNullOrWhiteSpace($ans)) {
return $Default
}
$ans = $ans.Trim().ToLower()
return $ans.StartsWith("s")
}
function Get-ConfigValue {
param(
[string]$Path,
[string]$Key
)
if (-not (Test-Path $Path)) { return "" }
$line = Get-Content $Path | Where-Object { $_ -match "^\s*$([regex]::Escape($Key))\s*=" } | Select-Object -First 1
if ($null -eq $line) { return "" }
return ($line -split "=",2)[1].Trim()
}
function Set-ConfigValue {
param(
[string]$Path,
[string]$Key,
[string]$Value
)
$Value = $Value.Trim()
if (-not (Test-Path $Path)) {
"$Key=$Value" | Set-Content -Path $Path -Encoding UTF8
return
}
$content = Get-Content $Path
$found = $false
for ($i = 0; $i -lt $content.Count; $i++) {
if ($content[$i] -match "^\s*$([regex]::Escape($Key))\s*=") {
$content[$i] = "$Key=$Value"
$found = $true
break
}
}
if (-not $found) {
$content += "$Key=$Value"
}
$content | Set-Content -Path $Path -Encoding UTF8
}
function Ensure-DefaultConfig {
param([string]$ConfigPath)
if (Test-Path $ConfigPath) { return }
Write-Host "File di configurazione non trovato, ne creo uno di base..." -ForegroundColor Yellow
@"
BackupRoot=C:\Backups_AdHoc
LocalRetentionDaysFiles=2
LocalRetentionDaysDb=2
RemoteRetentionDays=15
KeepLocalArchives=true
EnableFileBackup=true
EnableRcloneUpload=true
ArchiveSources=C:\Zucchetti\ahr90|C:\Zucchetti\NetSetup
EnableSqlBackup=true
SqlInstance=localhost\SQLEXPRESS
SqlUseWindowsAuth=true
SqlUser=sa
SqlPassword=
DbInclude=
DbExclude=master|model|msdb|tempdb
SqlCompressStage=true
SqlDropBakAfterZip=true
SevenZipCompressionLevel=1
RcloneRemoteDest=dropbox:/Backups_AdHoc/%COMPUTERNAME%
RcloneBwl=
RcloneExtraArgs=
MailEnabled=true
MailSmtpHost=relay.poloinformatico.it
MailSmtpPort=587
MailUseAuth=true
MailUser=
MailPassword=
MailFrom=backup@localhost
MailTo=it@poloinformatico.it
MailSubjectPref=[BACKUP ADHOC]
"@ | Set-Content -Path $ConfigPath -Encoding UTF8
}
function Get-BackupRootFromConfig {
param([string]$ConfigPath)
$br = Get-ConfigValue -Path $ConfigPath -Key "BackupRoot"
if ([string]::IsNullOrWhiteSpace($br)) {
$br = "C:\Backups_AdHoc"
}
return $br
}
# ==========================
# INSTALL 7ZIP / RCLONE STILE AdHoc-Backup.ps1
# ==========================
function Install-7Zip-LikeBackup {
param(
[string]$BackupRoot
)
$binDir = Join-Path $BackupRoot "Bin"
$bin7zDir = Join-Path $binDir "7zip"
Ensure-Folder $binDir
Ensure-Folder $bin7zDir
$sevenZipExe = Join-Path $bin7zDir "7z.exe"
$sevenZip7zr = Join-Path $bin7zDir "7zr.exe"
if (Test-Path $sevenZipExe -or Test-Path $sevenZip7zr) {
Write-Host "7-Zip già presente in $bin7zDir" -ForegroundColor Green
return
}
$dest = $sevenZip7zr
Write-Host "Scarico 7zip portable..." -ForegroundColor Cyan
Download-File -Url $SevenZipPortableUrl -Destination $dest
if (Test-Path $dest) {
Write-Host "7zip installato in $bin7zDir" -ForegroundColor Green
} else {
Write-Warning "7zip non scaricato."
}
}
function Install-Rclone-LikeBackup {
param(
[string]$BackupRoot
)
$binDir = Join-Path $BackupRoot "Bin"
$rcloneDir = Join-Path $binDir "RClone"
$rcloneExe = Join-Path $rcloneDir "rclone.exe"
$rcloneZip = Join-Path $rcloneDir "rclone-current-windows-amd64.zip"
$rcloneConf = Join-Path $rcloneDir "rclone.conf"
Ensure-Folder $binDir
Ensure-Folder $rcloneDir
if (-not (Test-Path $rcloneExe)) {
Write-Host "Scarico rclone..." -ForegroundColor Cyan
Download-File -Url $RcloneZipUrl -Destination $rcloneZip
try { Add-Type -AssemblyName System.IO.Compression.FileSystem | Out-Null } catch {}
[System.IO.Compression.ZipFile]::ExtractToDirectory($rcloneZip, $rcloneDir)
# dentro lo zip c'è una sottocartella, lo cerchiamo
$found = Get-ChildItem -LiteralPath $rcloneDir -Recurse -Filter 'rclone.exe' | Select-Object -First 1
if ($found) {
Copy-Item -LiteralPath $found.FullName -Destination $rcloneExe -Force
# pulisco le sottocartelle estratte
Get-ChildItem -LiteralPath $rcloneDir -Directory | ForEach-Object { Remove-Item $_.FullName -Recurse -Force }
} else {
Write-Warning "rclone.exe non trovato nello zip."
}
# rimuovo lo zip come richiesto
if (Test-Path $rcloneZip) {
Remove-Item $rcloneZip -Force
}
Write-Host "rclone installato in $rcloneDir" -ForegroundColor Green
} else {
Write-Host "rclone già presente in $rcloneDir" -ForegroundColor Green
}
# lancio configurazione come nello script originale
if (-not (Test-Path $rcloneConf)) {
Write-Host "Apro la configurazione di rclone in una nuova finestra..." -ForegroundColor Yellow
$cmd = " & `"$rcloneExe`" --config `"$rcloneConf`" config "
Start-Process -FilePath "powershell.exe" -ArgumentList "-NoExit","-Command",$cmd -WindowStyle Normal | Out-Null
} else {
Write-Host "rclone.conf già presente: $rcloneConf" -ForegroundColor Green
}
}
# ==========================
# FUNZIONE 2: PIANIFICAZIONE
# ==========================
function Create-BackupScheduledTask {
param(
[ValidateSet("Daily","Weekly")]
[string]$Mode = "Daily"
)
$backupScriptPath = Join-Path $InstallRoot $BackupScriptName
if (-not (Test-Path $backupScriptPath)) {
Write-Warning "Lo script di backup non è stato trovato in $backupScriptPath. Installa prima (opzione 1)."
return
}
Write-Host ""
Write-Host "Impostazione orario di esecuzione" -ForegroundColor Cyan
$hour = Read-Host "Inserisci l'ora di esecuzione (0-23) [default 22]"
if ([string]::IsNullOrWhiteSpace($hour)) { $hour = 22 }
$minute = Read-Host "Inserisci i minuti (0-59) [default 30]"
if ([string]::IsNullOrWhiteSpace($minute)) { $minute = 30 }
$time = New-TimeSpan -Hours ([int]$hour) -Minutes ([int]$minute)
$at = (Get-Date).Date + $time
if ($Mode -eq "Weekly") {
$day = Read-Host "Giorno della settimana (Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday) [default Monday]"
if ([string]::IsNullOrWhiteSpace($day)) { $day = "Monday" }
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek $day -At $at
} else {
$trigger = New-ScheduledTaskTrigger -Daily -At $at
}
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File `"$backupScriptPath`""
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
$taskName = "Backup AdHoc"
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force | Out-Null
Write-Host "Pianificazione '$taskName' creata in modalità $Mode alle $hour`:$minute." -ForegroundColor Green
}
function Show-ScheduleMenu {
Write-Host "== CREA PIANIFICAZIONE ==" -ForegroundColor Cyan
Write-Host "1) Giornaliera"
Write-Host "2) Settimanale"
Write-Host "0) Annulla"
$choice = Read-Host "Seleziona"
switch ($choice) {
"1" { Create-BackupScheduledTask -Mode Daily }
"2" { Create-BackupScheduledTask -Mode Weekly }
default { Write-Host "Nessuna pianificazione creata." }
}
}
# ==========================
# FUNZIONE 3: MODIFICA CONFIG
# ==========================
function Edit-BackupConfig {
param(
[string]$ConfigPath
)
if (-not (Test-Path $ConfigPath)) {
Write-Warning "File $ConfigPath non trovato. Lo creo adesso."
Ensure-DefaultConfig -ConfigPath $ConfigPath
}
$Descriptions = [ordered]@{
"BackupRoot" = "Cartella radice dove vanno archivi, log e tool."
"LocalRetentionDaysFiles" = "Giorni di conservazione FILE in locale."
"LocalRetentionDaysDb" = "Giorni di conservazione DATABASE in locale."
"RemoteRetentionDays" = "Giorni di conservazione su destinazione remota (rclone)."
"KeepLocalArchives" = "true = tiene una copia locale dopo l'upload."
"EnableFileBackup" = "true = esegue il backup delle cartelle in ArchiveSources."
"EnableRcloneUpload" = "true = dopo il backup carica su cloud tramite rclone."
"ArchiveSources" = "Elenco cartelle/sorgenti da salvare, separate da |."
"EnableSqlBackup" = "true = fa anche i backup dei database SQL Server."
"SqlInstance" = "Nome/istanza SQL Server (es. localhost\SQLEXPRESS)."
"SqlUseWindowsAuth" = "true = usa utente Windows; false = usa SqlUser/SqlPassword."
"SqlUser" = "Utente SQL (se SqlUseWindowsAuth=false)."
"SqlPassword" = "Password SQL (se SqlUseWindowsAuth=false)."
"DbInclude" = "Elenco DB da includere (se vuoto li prende tutti tranne gli esclusi)."
"DbExclude" = "DB da escludere quando DbInclude è vuoto."
"SqlCompressStage" = "true = comprime i .bak in .7z."
"SqlDropBakAfterZip" = "true = elimina i .bak dopo la compressione."
"SevenZipCompressionLevel" = "0..9 livello di compressione 7z (1=veloce, 9=max)."
"RcloneRemoteDest" = "Destinazione rclone: REMOTO:percorso."
"RcloneBwl" = "Limite banda rclone (es. 10M) oppure vuoto."
"RcloneExtraArgs" = "Argomenti extra rclone separati da |."
"MailEnabled" = "true = invia mail di report."
"MailSmtpHost" = "Server SMTP/relay."
"MailSmtpPort" = "Porta SMTP (es. 587)."
"MailUseAuth" = "true = il relay richiede utente/password."
"MailUser" = "Utente SMTP."
"MailPassword" = "Password SMTP."
"MailFrom" = "Mittente mail."
"MailTo" = "Destinatari (separati da |)."
"MailSubjectPref" = "Prefisso dell'oggetto mail."
}
Write-Host "== MODIFICA GUIDATA backup.conf ==" -ForegroundColor Cyan
foreach ($key in $Descriptions.Keys) {
$current = Get-ConfigValue -Path $ConfigPath -Key $key
Write-Host ""
Write-Host "$key" -ForegroundColor Yellow
Write-Host " $($Descriptions[$key])"
Write-Host " Valore attuale: $current"
$newVal = Read-Host " Nuovo valore (invio per lasciare quello attuale)"
if (-not [string]::IsNullOrWhiteSpace($newVal)) {
Set-ConfigValue -Path $ConfigPath -Key $key -Value $newVal
Write-Host " -> Aggiornato."
} else {
Write-Host " -> Lasciato invariato."
}
}
Write-Host ""
Write-Host "Configurazione aggiornata in $ConfigPath" -ForegroundColor Green
}
# ==========================
# FUNZIONE 4: ESEGUI PRIMO BACKUP
# ==========================
function Run-FirstBackup {
$backupScriptPath = Join-Path $InstallRoot $BackupScriptName
if (-not (Test-Path $backupScriptPath)) {
Write-Warning "Lo script $backupScriptPath non esiste. Esegui prima l'installazione (1)."
return
}
Write-Host "Eseguo il primo backup..." -ForegroundColor Cyan
# lo eseguiamo nello stesso PowerShell così lutente vede loutput
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $backupScriptPath
}
# ==========================
# FUNZIONE 1: INSTALLA
# ==========================
function Install-AdHocBackup {
Write-Host "== INSTALLAZIONE SCRIPT BACKUP ==" -ForegroundColor Cyan
Ensure-Folder -Path $InstallRoot
foreach ($entry in $DownloadMap.GetEnumerator()) {
$fileName = $entry.Key
$url = $entry.Value
$dest = Join-Path $InstallRoot $fileName
Download-File -Url $url -Destination $dest
}
$configPath = Join-Path $InstallRoot $ConfigFileName
Ensure-DefaultConfig -ConfigPath $configPath
# ora che abbiamo il config, vediamo il BackupRoot per installare 7zip/rclone negli stessi percorsi
$backupRoot = Get-BackupRootFromConfig -ConfigPath $configPath
Ensure-Folder $backupRoot
Install-7Zip-LikeBackup -BackupRoot $backupRoot
Install-Rclone-LikeBackup -BackupRoot $backupRoot
# Chiede subito se vuole pianificare
if (Read-YesNo "Vuoi creare una pianificazione (operazione consigliata)?" $true) {
Show-ScheduleMenu
}
# Chiede subito se vuole modificare configurazione
if (Read-YesNo "Vuoi modificare adesso la configurazione del file backup.conf?" $false) {
Edit-BackupConfig -ConfigPath $configPath
}
Write-Host "Installazione completata." -ForegroundColor Green
}
# ==========================
# MENÙ PRINCIPALE
# ==========================
do {
Write-Host ""
Write-Host "==============================" -ForegroundColor DarkCyan
Write-Host " INSTALL ADHOC BACKUP - MENU"
Write-Host "==============================" -ForegroundColor DarkCyan
Write-Host "1) Installa / aggiorna script (scarica da gitea, installa 7zip e rclone)"
Write-Host "2) Crea pianificazione (giornaliera/settimanale, con orario)"
Write-Host "3) Modifica configurazione backup.conf (guidata)"
Write-Host "4) Esegui il primo backup"
Write-Host "0) Chiudi la finestra"
$sel = Read-Host "Seleziona"
$configPath = Join-Path $InstallRoot $ConfigFileName
switch ($sel) {
"1" { Install-AdHocBackup }
"2" { Show-ScheduleMenu }
"3" { Edit-BackupConfig -ConfigPath $configPath }
"4" { Run-FirstBackup }
"0" { Stop-Process -Id $PID }
default { Write-Host "Scelta non valida." -ForegroundColor Red }
}
} while ($true)