Aller au contenu principal

Script d'extraction de sauvegardes Unifi

Ce document explique et inclut le script PowerShell utilisé pour extraire les sauvegardes Unifi par SSH avec Putty.
En gros, si vous avez un système de sécurité sans accès WAN, cela permet de sauvegarder les données Unifi vers un serveur LAN.


Aperçu​

Le script se connecte à un appareil Unifi via SSH, récupère la liste des fichiers de sauvegarde, les compare avec le répertoire local et télécharge automatiquement ceux qui manquent.
Il utilise les utilitaires PuTTY (plink et pscp) pour la communication SSH et les transferts de fichiers.


Paramètres​

ParamètreDescription
unifiUserRootNom d'utilisateur SSH pour l'appareil Unifi (par défaut : root).
unifiDeviceAdresse IP de l'appareil Unifi.
unifiBackupDirChemin du répertoire distant contenant les sauvegardes Unifi.
passwordMot de passe SSH pour l'utilisateur Unifi.
localDirRépertoire local où les sauvegardes seront stockées.

Comment fonctionne le script​

Étape 1. Vérifier le répertoire local​

Le script s'assure que le répertoire local existe avant de continuer.
Sinon, il se termine pour éviter les erreurs.

if (-not (Test-Path $localDir)) {
Write-Host "Local directory does not exist: $localDir"
exit 1
}

Étape 2. Récupérer l'empreinte SSH​

Pour vérifier l'identité de l'appareil Unifi, le script récupère son empreinte SSH et s'assure que la connexion est sécurisée.

$hostKeyScan = & ssh-keyscan -t ed25519 $unifiDevice 2>$null
$hostKeyFingerprint = $hostKeyScan | ssh-keygen -lf - | ForEach-Object {
$_.ToString().Split(" ") | Select-Object -Index 1
}

Cela prévient les attaques de type « man-in-the-middle » en confirmant que la clé SSH correspond à l'appareil attendu.


Étape 3. Récupérer la liste des sauvegardes distantes​

Le script se connecte via plink et liste tous les fichiers du répertoire de sauvegarde Unifi.

$unifiBackups = & "$plinkPath" `
-ssh `
-pw $password `
-batch `
-noagent `
-hostkey "$fullHostKey" `
"$unifiUserRoot@$unifiDevice" `
"ls -1 $unifiBackupDir"

Étape 4. Comparer avec les fichiers locaux​

Il compare la liste des sauvegardes distantes avec les fichiers locaux pour trouver ceux qui manquent.

$localFiles = Get-ChildItem -Path $localDir -File | Select-Object -ExpandProperty Name
$missingBackups = $unifiBackups | Where-Object { $_ -and ($_ -notin $localFiles) }

S'il n'y a aucun fichier manquant, le script se termine normalement.


Étape 5. Télécharger les sauvegardes manquantes​

Pour chaque fichier manquant, le script le télécharge en utilisant pscp via SSH.

foreach ($file in $missingBackups) {
$remoteFullPath = "$unifiUserRoot@$unifiDevice:$unifiBackupDir/$file"
& "$pscpPath" -pw $password -batch -noagent -hostkey $fullHostKey $remoteFullPath $localDir
}

Une fois terminé, il signale que tous les fichiers manquants ont été téléchargés.


Exemple d'utilisation​

Pour exécuter le script :

.\BackupUnifi.ps1

Avant l'exécution :

  • Assurez-vous que plink.exe et pscp.exe (de PuTTY) sont installés.
  • Vérifiez l'adresse IP Unifi et les identifiants SSH.
  • Assurez-vous que le répertoire de sauvegarde local existe et a les permissions d'écriture.

Code source complet​

# SPDX-License-Identifier: AGPL-3.0-or-later
#
# This file is part of the "Unifi Automatic Backup Script via SSH".
#
# Copyright (C) 2025 Mat Ice
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
<#
.SYNOPSIS
Automatically backs up Unifi configuration files over SSH.

.DESCRIPTION
It connects to a Unifi device via SSH, retrieves the list of backup files,
compares them with the local ones, and automatically downloads any that are missing.

.PARAMETER unifiUserRoot
SSH username for connecting to the Unifi device (default: "root").

.PARAMETER unifiDevice
IP address of the Unifi device.

.PARAMETER unifiBackupDir
Remote directory containing Unifi backups.

.PARAMETER password
SSH password for the Unifi user.

.PARAMETER localDir
Local directory where backups will be stored.

.EXAMPLE
.\BackupUnifi.ps1

.NOTES
Author : Mat Ice
#>

$unifiUserRoot = "root"
$unifiDevice = "192.168.2.1"
$unifiBackupDir = "/data/unifi/data/backup/autobackup"
$password = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
$localDir = "G:\unifi"

# Path to PuTTY tools (adjust if needed)
$pscpPath = "C:\Program Files\PuTTY\pscp.exe"
$plinkPath = "C:\Program Files\PuTTY\plink.exe"

# === STEP 0: Verify local directory ===
if (-not (Test-Path $localDir)) {
Write-Host "Local directory does not exist: $localDir"
exit 1
}

# === STEP 1: Retrieve SSH host key fingerprint ===
Write-Host "Retrieving SSH host key fingerprint..."
$hostKeyScan = & ssh-keyscan -t ed25519 $unifiDevice 2>$null

if (-not $hostKeyScan) {
Write-Host "Failed to retrieve SSH key from $unifiDevice"
exit 1
}

# Generate SHA256 fingerprint (requires OpenSSH)
$hostKeyFingerprint = $hostKeyScan | ssh-keygen -lf - | ForEach-Object {
$_.ToString().Split(" ") | Select-Object -Index 1
}

if (-not $hostKeyFingerprint) {
Write-Host "Failed to parse fingerprint."
exit 1
}

$fullHostKey = "ssh-ed25519 255 $hostKeyFingerprint"
Write-Host "Using host key fingerprint: $fullHostKey"

# === STEP 2: Retrieve remote backup list ===
Write-Host "Fetching file list from remote Unifi device..."
try {
$unifiBackups = & "$plinkPath" `
-ssh `
-pw $password `
-batch `
-noagent `
-hostkey "$fullHostKey" `
"$unifiUserRoot@$unifiDevice" `
"ls -1 $unifiBackupDir"
} catch {
Write-Host "Failed to retrieve remote file list: $_"
exit 1
}

if (-not $unifiBackups) {
Write-Host "No backup files found or SSH command failed."
exit 1
}

# === STEP 3: Retrieve local files ===
$localFiles = Get-ChildItem -Path $localDir -File | Select-Object -ExpandProperty Name

# === STEP 4: Compare and download missing backups ===
$missingBackups = $unifiBackups | Where-Object { $_ -and ($_ -notin $localFiles) }

if ($missingBackups.Count -eq 0) {
Write-Host "All backups are already present locally. Nothing to download."
exit 0
}

foreach ($file in $missingBackups) {
$remoteFilePath = "$unifiBackupDir/$file"
$localFilePath = Join-Path $localDir $file

Write-Host "Downloading: $file"
try {
$remoteFullPath = "$unifiUserRoot@$unifiDevice" + ":$remoteFilePath"

$arguments = @(
'-pw', $password,
'-batch',
'-noagent',
'-hostkey', $fullHostKey,
$remoteFullPath,
$localFilePath
)

& "$pscpPath" @arguments
}
catch {
Write-Host "Failed to download $file : $_"
}
}

Write-Host "All missing backup files have been downloaded successfully."

Résumé​

Ce script PowerShell automatise les sauvegardes de configuration Unifi via SSH.
Il assure que les sauvegardes de votre appareil Unifi sont mirrorées de manière sécurisée sur un serveur LAN, minimisant le risque de perte de configuration.