mirror of
https://github.com/beeyev/Mikrotik-RouterOS-automatic-backup-and-update.git
synced 2025-08-29 06:18:36 +02:00
Compare commits
No commits in common. "master" and "25.04.12" have entirely different histories.
3 changed files with 496 additions and 441 deletions
|
@ -13,7 +13,7 @@ insert_final_newline = true
|
||||||
|
|
||||||
[*.rsc]
|
[*.rsc]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 4
|
||||||
|
|
||||||
[*.{yml,yaml,sls}]
|
[*.{yml,yaml,sls}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
# Script name: BackupAndUpdate
|
# Script name: BackupAndUpdate
|
||||||
#
|
#
|
||||||
# SCRIPT INFORMATION
|
#----------SCRIPT INFORMATION---------------------------------------------------
|
||||||
#
|
#
|
||||||
# Script: Mikrotik RouterOS automatic backup & update
|
# Script: Mikrotik RouterOS automatic backup & update
|
||||||
# Version: 25.04.15
|
# Version: 25.04.12
|
||||||
# Created: 07/08/2018
|
# Created: 07/08/2018
|
||||||
# Updated: 15/04/2025
|
# Updated: 12/04/2025
|
||||||
# Author: Alexander Tebiev
|
# Author: Alexander Tebiev
|
||||||
# Website: https://github.com/beeyev
|
# Website: https://github.com/beeyev
|
||||||
# You can contact me by e-mail at tebiev@mail.com
|
# You can contact me by e-mail at tebiev@mail.com
|
||||||
|
@ -13,50 +13,54 @@
|
||||||
# IMPORTANT!
|
# IMPORTANT!
|
||||||
# Minimum supported RouterOS version is v6.43.7
|
# Minimum supported RouterOS version is v6.43.7
|
||||||
#
|
#
|
||||||
# --- MODIFY THIS SECTION AS NEEDED ---
|
#----------MODIFY THIS SECTION AS NEEDED----------------------------------------
|
||||||
# Notification e-mail
|
## Notification e-mail
|
||||||
# (Make sure you have configured Email settings in Tools -> Email)
|
## (Make sure you have configured Email settings in Tools -> Email)
|
||||||
:local emailAddress "yourmail@example.com";
|
:local emailAddress "yourmail@example.com";
|
||||||
|
|
||||||
# Script mode, possible values: backup, osupdate, osnotify.
|
## Script mode, possible values: backup, osupdate, osnotify.
|
||||||
# backup - Only backup will be performed. (default value, if none provided)
|
# backup - Only backup will be performed. (default value, if none provided)
|
||||||
#
|
#
|
||||||
# osupdate - Installs new RouterOS if available and creates backups before/after update (ignores `forceBackup`)
|
# osupdate - The script will install a new RouterOS version if it is available.
|
||||||
# Sends email only when an update is found.
|
# It will also create backups before and after update process (it does not matter what value `forceBackup` is set to)
|
||||||
# Set `forceBackup` to true to always create backups, even without updates
|
# Email will be sent only if a new RouterOS version is available.
|
||||||
|
# Change parameter `forceBackup` if you need the script to create backups every time when it runs (even when no updates were found).
|
||||||
#
|
#
|
||||||
# osnotify - Sends email only if a new RouterOS update is found (no backups)
|
# osnotify - The script will send email notifications only (without backups) if a new RouterOS update is available.
|
||||||
# Set `forceBackup` to always create backups on every run
|
# Change parameter `forceBackup` if you need the script to create backups every time when it runs.
|
||||||
:local scriptMode "osupdate"
|
:local scriptMode "osupdate"
|
||||||
|
|
||||||
# Additional parameter if you set `scriptMode` to `osupdate` or `osnotify`
|
## Additional parameter if you set `scriptMode` to `osupdate` or `osnotify`
|
||||||
# Set `true` if you want the script to perform backup every time its fired, whatever script mode is set.
|
# Set `true` if you want the script to perform backup every time its fired, whatever script mode is set.
|
||||||
:local forceBackup false
|
:local forceBackup false
|
||||||
|
|
||||||
# Backup encryption password, no encryption if no password.
|
## Backup encryption password, no encryption if no password.
|
||||||
:local backupPassword ""
|
:local backupPassword ""
|
||||||
|
|
||||||
# If true, passwords will be included in exported config.
|
## If true, passwords will be included in exported config.
|
||||||
:local sensitiveDataInConfig true
|
:local sensitiveDataInConfig true
|
||||||
|
|
||||||
## Update channel. Possible values: stable, long-term, testing, development
|
## Update channel. Possible values: stable, long-term, testing, development
|
||||||
:local updateChannel "stable"
|
:local updateChannel "stable"
|
||||||
|
|
||||||
# Installs patch updates only (scriptMode = "osupdate").
|
## Install only patch updates (requires scriptMode = "osupdate")
|
||||||
# Works for `stable` and `long-term` channels.
|
## Works only for `stable` and `long-term` channels.
|
||||||
# Updates only if MAJOR.MINOR match (e.g. 6.43.2 → 6.43.6 allowed, 6.44.1 skipped).
|
## Update will run only if MAJOR and MINOR versions match the current one
|
||||||
# Sends info if a newer (non-patch) version is found.
|
## Example: current = v6.43.2 → v6.43.6 = allowed, v6.44.1 = skipped
|
||||||
|
## Script will send information if new version is greater than just patch.
|
||||||
:local installOnlyPatchUpdates false
|
:local installOnlyPatchUpdates false
|
||||||
|
|
||||||
# Include public IP info in email if set to true
|
## If true, device public IP address information will be included into the email message
|
||||||
:local detectPublicIpAddress true
|
:local detectPublicIpAddress true
|
||||||
|
|
||||||
## Allow anonymous statistics collection. (script mode and generic non-sensitive device info)
|
## Allow anonymous statistics collection. (script mode and generic non-sensitive device info)
|
||||||
:local anonStats true
|
:local allowAnonymousStatisticsCollection true
|
||||||
|
|
||||||
# !!! DO NOT EDIT BELOW THIS LINE UNLESS YOU KNOW WHAT YOU’RE DOING !!!
|
##------------------------------------------------------------------------------------------##
|
||||||
|
# !!!! DO NOT CHANGE ANYTHING BELOW THIS LINE, IF YOU ARE NOT SURE WHAT YOU ARE DOING !!!! #
|
||||||
|
##------------------------------------------------------------------------------------------##
|
||||||
|
|
||||||
:local scriptVersion "25.04.15"
|
:local scriptVersion "25.04.12"
|
||||||
|
|
||||||
# default and fallback public IP detection services
|
# default and fallback public IP detection services
|
||||||
:local ipAddressDetectServiceDefault "https://ipv4.mikrotik.ovh/"
|
:local ipAddressDetectServiceDefault "https://ipv4.mikrotik.ovh/"
|
||||||
|
@ -69,17 +73,21 @@
|
||||||
:log info "\n\n$SMP Script \"Mikrotik RouterOS automatic backup & update\" v.$scriptVersion started."
|
:log info "\n\n$SMP Script \"Mikrotik RouterOS automatic backup & update\" v.$scriptVersion started."
|
||||||
:log info "$SMP Script Mode: `$scriptMode`, Update channel: `$updateChannel`, Force backup: `$forceBackup`, Install only patch updates: `$installOnlyPatchUpdates`"
|
:log info "$SMP Script Mode: `$scriptMode`, Update channel: `$updateChannel`, Force backup: `$forceBackup`, Install only patch updates: `$installOnlyPatchUpdates`"
|
||||||
|
|
||||||
## vv FUNCTIONS vv ##
|
############### vvvvvvvvv FUNCTIONS vvvvvvvvv ###############
|
||||||
|
|
||||||
|
# Function: FuncGetRunningOsVersion
|
||||||
|
# ----------------------------
|
||||||
# Returns currently running RouterOS version
|
# Returns currently running RouterOS version
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
# :put [$FuncGetRunningOsVersion] # Output: 6.48.1
|
# :put [$FuncGetRunningOsVersion] # Output: 6.48.1
|
||||||
:local FuncGetRunningOsVersion do={
|
:local FuncGetRunningOsVersion do={
|
||||||
:local runningOsAndChannel [/system resource get version]
|
:local runningOsAndChannel [/system resource get version]
|
||||||
|
|
||||||
:local spacePos [:find $runningOsAndChannel " "]
|
:local spacePos [:find $runningOsAndChannel " "]
|
||||||
:if ([:len $spacePos] = 0) do={
|
:if ([:len $spacePos] = 0) do={
|
||||||
:log error "Bkp&Upd: Could not extract installed OS version string: `$runningOsAndChannel`."
|
:log error "Bkp&Upd: Could not extract installed OS version string: `$runningOsAndChannel`. Script stopped."
|
||||||
:error "Bkp&Upd: error, check logs"
|
:error "Bkp&Upd: script stopped due to an error. Please check logs for more details."
|
||||||
}
|
}
|
||||||
|
|
||||||
:local versionOnly [:pick $runningOsAndChannel 0 $spacePos]
|
:local versionOnly [:pick $runningOsAndChannel 0 $spacePos]
|
||||||
|
@ -87,32 +95,59 @@
|
||||||
:return $versionOnly
|
:return $versionOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
# Returns currently running RouterOS channel
|
# Function: FuncGetRunningOsChannel
|
||||||
|
# ----------------------------
|
||||||
|
# Returns currently running RouterOS channel (stable, long-term, testing, development)
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
# :put [$FuncGetRunningOsChannel] # Output: stable
|
# :put [$FuncGetRunningOsChannel] # Output: stable
|
||||||
:local FuncGetRunningOsChannel do={
|
:local FuncGetRunningOsChannel do={
|
||||||
:local runningOsAndChannel [/system resource get version]
|
:local runningOsAndChannel [/system resource get version]
|
||||||
|
:local errorMessage "Bkp&Upd: Could not extract installed OS channel from version string: `$runningOsAndChannel`. Script stopped."
|
||||||
|
:local exitErrorMessage "Bkp&Upd: script stopped due to an error. Please check logs for more details."
|
||||||
|
|
||||||
:local open [:find $runningOsAndChannel "("]
|
:local open [:find $runningOsAndChannel "("]
|
||||||
:if ([:len $open] = 0) do={
|
:if ([:len $open] = 0) do={
|
||||||
:log error "Bkp&Upd: Could not extract installed OS channel from version string: `$runningOsAndChannel`."
|
:log error ($errorMessage . " (1)")
|
||||||
:error "Bkp&Upd: error, check logs"
|
:error $exitErrorMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
:local rest [:pick $runningOsAndChannel ($open+1) [:len $runningOsAndChannel]]
|
:local rest [:pick $runningOsAndChannel ($open+1) [:len $runningOsAndChannel]]
|
||||||
|
|
||||||
:local close [:find $rest ")"]
|
:local close [:find $rest ")"]
|
||||||
|
:if ([:len $close] = 0) do={
|
||||||
|
:log error ($errorMessage . " (2)")
|
||||||
|
:error $exitErrorMessage
|
||||||
|
}
|
||||||
|
|
||||||
:local channel [:pick $rest 0 $close]
|
:local channel [:pick $rest 0 $close]
|
||||||
|
:if ([:len $channel] = 0) do={
|
||||||
|
:log error ($errorMessage . " (3)")
|
||||||
|
:error $exitErrorMessage
|
||||||
|
}
|
||||||
|
|
||||||
:return $channel
|
:return $channel
|
||||||
}
|
}
|
||||||
|
|
||||||
# Checks if two RouterOS version strings differ only by the patch version
|
# Function: FuncIsPatchUpdateOnly
|
||||||
|
# ----------------------------
|
||||||
|
# Determines if two RouterOS version strings differ only by the patch version.
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# `version1` | string | The first version string (e.g., "6.2.1").
|
||||||
|
# `version2` | string | The second version string (e.g., "6.2.4").
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# boolean | true if only the patch versions differ; false otherwise.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
# :put [$FuncIsPatchUpdateOnly "6.2.1" "6.2.4"] # Output: true
|
# :put [$FuncIsPatchUpdateOnly "6.2.1" "6.2.4"] # Output: true
|
||||||
# :put [$FuncIsPatchUpdateOnly "6.2.1" "6.3.1"] # Output: false
|
# :put [$FuncIsPatchUpdateOnly "6.2.1" "6.3.1"] # Output: false
|
||||||
:local FuncIsPatchUpdateOnly do={
|
:local FuncIsPatchUpdateOnly do={
|
||||||
:local ver1 $1
|
:local ver1 $1
|
||||||
:local ver2 $2
|
:local ver2 $2
|
||||||
|
|
||||||
# Extract the major and minor components from a version
|
# Internal function to extract the major and minor components from a version string.
|
||||||
:local extractMajorMinor do={
|
:local extractMajorMinor do={
|
||||||
:local ver $1
|
:local ver $1
|
||||||
:local dot1 [:find $ver "."]
|
:local dot1 [:find $ver "."]
|
||||||
|
@ -127,18 +162,18 @@
|
||||||
:return ($major . "." . $minor)
|
:return ($major . "." . $minor)
|
||||||
}
|
}
|
||||||
|
|
||||||
# Compare the major and minor components of both version strings
|
# Compare the major and minor components of both version strings.
|
||||||
:if ([$extractMajorMinor $ver1] = [$extractMajorMinor $ver2]) do={
|
:if ([$extractMajorMinor $ver1] = [$extractMajorMinor $ver2]) do={
|
||||||
:return true
|
:return true
|
||||||
}
|
}
|
||||||
:return false
|
:return false
|
||||||
}
|
}
|
||||||
|
|
||||||
# Creates backups and returns array of names
|
# Function creates backups (system and config) and returns array of names of created files.
|
||||||
# Possible arguments:
|
# Possible arguments:
|
||||||
# $1 - file name, without extension
|
# `backupName` | string | backup file name, without extension!
|
||||||
# $2 - password (optional)
|
# `backupPassword` | string |
|
||||||
# $3 - sensitive data in config (optional, default: false)
|
# `sensitiveDataInConfig` | boolean |
|
||||||
# Example:
|
# Example:
|
||||||
# :put [$FuncCreateBackups "daily-backup"]
|
# :put [$FuncCreateBackups "daily-backup"]
|
||||||
:local FuncCreateBackups do={
|
:local FuncCreateBackups do={
|
||||||
|
@ -189,7 +224,7 @@
|
||||||
:log info ("$SMP Config export complete: `$backupFileConfig`")
|
:log info ("$SMP Config export complete: `$backupFileConfig`")
|
||||||
:log info ("$SMP Waiting a little to ensure backup files are written")
|
:log info ("$SMP Waiting a little to ensure backup files are written")
|
||||||
|
|
||||||
:delay 40s
|
:delay 20s
|
||||||
|
|
||||||
:if ([:len [/file find name=$backupFileSys]] > 0) do={
|
:if ([:len [/file find name=$backupFileSys]] > 0) do={
|
||||||
:log info ("$SMP system backup file successfully saved to the file system: `$backupFileSys`")
|
:log info ("$SMP system backup file successfully saved to the file system: `$backupFileSys`")
|
||||||
|
@ -210,7 +245,10 @@
|
||||||
:return $backupNames
|
:return $backupNames
|
||||||
}
|
}
|
||||||
|
|
||||||
# Sends an email
|
# Function: FuncSendEmailSafe
|
||||||
|
# ---------------------------
|
||||||
|
# Sends an email and checks if it was sent successfully.
|
||||||
|
#
|
||||||
# Parameters:
|
# Parameters:
|
||||||
# $1 - to (email address)
|
# $1 - to (email address)
|
||||||
# $2 - subject
|
# $2 - subject
|
||||||
|
@ -218,7 +256,11 @@
|
||||||
# $4 - file attachments (optional; pass "" if not needed)
|
# $4 - file attachments (optional; pass "" if not needed)
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
|
# :do {
|
||||||
# $FuncSendEmailSafe "admin@domain.com" "Backup Done" "Backup complete." "backup1.backup"
|
# $FuncSendEmailSafe "admin@domain.com" "Backup Done" "Backup complete." "backup1.backup"
|
||||||
|
# } on-error={
|
||||||
|
# :log error "Email failed to send"
|
||||||
|
# }
|
||||||
:local FuncSendEmailSafe do={
|
:local FuncSendEmailSafe do={
|
||||||
|
|
||||||
:local emailTo $1
|
:local emailTo $1
|
||||||
|
@ -290,7 +332,7 @@
|
||||||
:if ([:len $scriptStep] = 0) do={
|
:if ([:len $scriptStep] = 0) do={
|
||||||
:set scriptStep 1
|
:set scriptStep 1
|
||||||
}
|
}
|
||||||
## ^^ FUNCTIONS ^^ ##
|
############### ^^^^^^^^^ FUNCTIONS ^^^^^^^^^ ###############
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -299,7 +341,7 @@
|
||||||
|
|
||||||
## Check email settings
|
## Check email settings
|
||||||
:if ([:len $emailAddress] < 3) do={
|
:if ([:len $emailAddress] < 3) do={
|
||||||
:log error ("$SMP Parameter `\$emailAddress` is not set, or contains invalid value. Script stopped.")
|
:log error ("$SMP Script parameter `\$emailAddress` is not set, or contains invalid value. Script stopped.")
|
||||||
:error $exitErrorMessage
|
:error $exitErrorMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,11 +357,11 @@
|
||||||
:set emailServer [/tool e-mail get address]
|
:set emailServer [/tool e-mail get address]
|
||||||
}
|
}
|
||||||
:if ($emailServer = "0.0.0.0") do={
|
:if ($emailServer = "0.0.0.0") do={
|
||||||
:log error ("$SMP Email server address is not correct: `$emailServer`, check `Tools -> Email`. Script stopped.");
|
:log error ("$SMP Email server address is not correct: `$emailServer`, please check `Tools -> Email`. Script stopped.");
|
||||||
:error $exitErrorMessage
|
:error $exitErrorMessage
|
||||||
}
|
}
|
||||||
:if ([:len $emailFromAddress] < 3) do={
|
:if ([:len $emailFromAddress] < 3) do={
|
||||||
:log error ("$SMP Email configuration FROM address is not correct: `$emailFromAddress`, check `Tools -> Email`. Script stopped.");
|
:log error ("$SMP Email configuration FROM address is not correct: `$emailFromAddress`, please check `Tools -> Email`. Script stopped.");
|
||||||
:error $exitErrorMessage
|
:error $exitErrorMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,34 +377,34 @@
|
||||||
:error $exitErrorMessage
|
:error $exitErrorMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
# Verify if script is set to install patch updates and if the update channel is valid
|
# Check if the script is set to install only patch updates and if the update channel is valid
|
||||||
:if ($scriptMode = "osupdate" and $installOnlyPatchUpdates = true) do={
|
:if ($scriptMode = "osupdate" and $installOnlyPatchUpdates = true) do={
|
||||||
:if ($updateChannel != "stable" and $updateChannel != "long-term") do={
|
:if ($updateChannel != "stable" and $updateChannel != "long-term") do={
|
||||||
:log error ("$SMP Patch-only updates enabled, but update channel `$updateChannel` is invalid. Only `stable` and `long-term` are supported. Script stopped")
|
:log error ("$SMP Script is set to install only patch updates, but the update channel is not valid: `$updateChannel`. Only `stable` and `long-term` channels supported. Script stopped.")
|
||||||
:error $exitErrorMessage
|
:error $exitErrorMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
:local susRunningOsChannel [$FuncGetRunningOsChannel]
|
:local susRunningOsChannel [$FuncGetRunningOsChannel]
|
||||||
|
|
||||||
:if ($susRunningOsChannel != "stable" and $susRunningOsChannel != "long-term") do={
|
:if ($susRunningOsChannel != "stable" and $susRunningOsChannel != "long-term") do={
|
||||||
:log error ("$SMP Script is set to install only patch updates, but the installed RouterOS version is not from `stable` or `long-term` channel: `$susRunningOsChannel`. Script stopped")
|
:log error ("$SMP Script is set to install only patch updates, but the installed RouterOS version is not from `stable` or `long-term` channel: `$susRunningOsChannel`. Script stopped.")
|
||||||
:error $exitErrorMessage
|
:error $exitErrorMessage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# Get current date and time
|
# Get current system date and time
|
||||||
#
|
#
|
||||||
:local rawTime [/system clock get time]
|
:local rawTime [/system clock get time]
|
||||||
:local rawDate [/system clock get date]
|
:local rawDate [/system clock get date]
|
||||||
|
|
||||||
# Current time in specific format `hh-mm-ss`
|
## Current time in specific format `hh-mm-ss`
|
||||||
:local currentTime ([:pick $rawTime 0 2] . "-" . [:pick $rawTime 3 5] . "-" . [:pick $rawTime 6 8])
|
:local currentTime ([:pick $rawTime 0 2] . "-" . [:pick $rawTime 3 5] . "-" . [:pick $rawTime 6 8])
|
||||||
|
|
||||||
# Current date `YYYY-MM-DD` or `YYYY-Mon-DD`
|
## Current date `YYYY-MM-DD` or `YYYY-Mon-DD`, will be defined later in the script
|
||||||
:local currentDate "undefined"
|
:local currentDate "undefined"
|
||||||
|
|
||||||
# Check if the date is in the old format
|
## Check if the date is in the old format, it should not start with a number
|
||||||
:if ([:len [:tonum [:pick $rawDate 0 1]]] = 0) do={
|
:if ([:len [:tonum [:pick $rawDate 0 1]]] = 0) do={
|
||||||
# Convert old format `nov/11/2023` → `2023-nov-11`
|
# Convert old format `nov/11/2023` → `2023-nov-11`
|
||||||
:set currentDate ([:pick $rawDate 7 11] . "-" . [:pick $rawDate 0 3] . "-" . [:pick $rawDate 4 6])
|
:set currentDate ([:pick $rawDate 7 11] . "-" . [:pick $rawDate 0 3] . "-" . [:pick $rawDate 4 6])
|
||||||
|
@ -371,11 +413,14 @@
|
||||||
:set currentDate $rawDate
|
:set currentDate $rawDate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## Combine date and time → `YYYY-MM-DD-hh-mm-ss` or `YYYY-Mon-DD-hh-mm-ss`
|
||||||
:local currentDateTime ($currentDate . "-" . $currentTime)
|
:local currentDateTime ($currentDate . "-" . $currentTime)
|
||||||
|
|
||||||
|
#####
|
||||||
|
|
||||||
:local deviceBoardName [/system resource get board-name]
|
:local deviceBoardName [/system resource get board-name]
|
||||||
|
|
||||||
## Check if it's a cloud hosted router
|
## Check if it's a cloud hosted router or a hardware based device
|
||||||
:local isCloudHostedRouter false;
|
:local isCloudHostedRouter false;
|
||||||
:if ([:pick $deviceBoardName 0 3] = "CHR" or [:pick $deviceBoardName 0 3] = "x86") do={
|
:if ([:pick $deviceBoardName 0 3] = "CHR" or [:pick $deviceBoardName 0 3] = "x86") do={
|
||||||
:set isCloudHostedRouter true;
|
:set isCloudHostedRouter true;
|
||||||
|
@ -427,44 +472,45 @@
|
||||||
|
|
||||||
:local mailAttachments [:toarray ""]
|
:local mailAttachments [:toarray ""]
|
||||||
|
|
||||||
## IP address detection
|
## IP address detection & anonymous statistics collection
|
||||||
:if ($scriptStep = 1 or $scriptStep = 3) do={
|
:if ($scriptStep = 1 or $scriptStep = 3) do={
|
||||||
:if ($scriptStep = 3) do={
|
:if ($scriptStep = 3) do={
|
||||||
:log info ("$SMP Waiting for one minute before continuing to the final step.")
|
:log info ("$SMP Waiting for one minute before continuing to the final step.")
|
||||||
:delay 1m
|
:delay 1m
|
||||||
}
|
}
|
||||||
# default values
|
# default values, to be set later
|
||||||
:local publicIpAddress "not-detected"
|
:local publicIpAddress "not-detected"
|
||||||
:local telemetryDataQuery ""
|
:local telemetryDataQuery ""
|
||||||
|
|
||||||
:if ($detectPublicIpAddress = true or $anonStats = true) do={
|
:if ($detectPublicIpAddress = true or $allowAnonymousStatisticsCollection = true) do={
|
||||||
:if ($anonStats = true) do={
|
:if ($allowAnonymousStatisticsCollection = true) do={
|
||||||
:set telemetryDataQuery ("\?mode=" . $scriptMode . "&scriptver=" . $scriptVersion . "&updatechannel=" . $updateChannel . "&osver=" . $runningOsVersion . "&step=" . $scriptStep . "&forcebackup=" . $forceBackup . "&onlypatchupdates=" . $installOnlyPatchUpdates . "&model=" . $deviceRbModel . "&deviceboard=" . $deviceBoardName)
|
:set telemetryDataQuery ("\?mode=" . $scriptMode . "&scriptver=" . $scriptVersion . "&updatechannel=" . $updateChannel . "&osver=" . $runningOsVersion . "&step=" . $scriptStep . "&forcebackup=" . $forceBackup . "&onlypatchupdates=" . $installOnlyPatchUpdates . "&model=" . $deviceRbModel . "&deviceboard=" . $deviceBoardName)
|
||||||
}
|
}
|
||||||
|
|
||||||
:do {:set publicIpAddress ([/tool fetch http-method="get" url=($ipAddressDetectServiceDefault . $telemetryDataQuery) output=user as-value]->"data")} on-error={
|
:do {:set publicIpAddress ([/tool fetch http-method="get" url=($ipAddressDetectServiceDefault . $telemetryDataQuery) output=user as-value]->"data")} on-error={
|
||||||
:if ($detectPublicIpAddress = true) do={
|
:if ($detectPublicIpAddress = true) do={
|
||||||
:log warning "$SMP Failed to detect public IP using default service: `$ipAddressDetectServiceDefault`"
|
:log warning "$SMP Could not detect public IP address using default detection service: `$ipAddressDetectServiceDefault`"
|
||||||
:log warning "$SMP Trying fallback service: `$ipAddressDetectServiceFallback`"
|
:log warning "$SMP Trying to detect public IP using fallback detection service: `$ipAddressDetectServiceFallback`"
|
||||||
|
:do {
|
||||||
:do {:set publicIpAddress ([/tool fetch http-method="get" url=$ipAddressDetectServiceFallback output=user as-value]->"data")} on-error={
|
:set publicIpAddress ([/tool fetch http-method="get" url=$ipAddressDetectServiceFallback output=user as-value]->"data")
|
||||||
|
} on-error={
|
||||||
:log warning "$SMP Could not detect public IP address using fallback detection service: `$ipAddressDetectServiceFallback`"
|
:log warning "$SMP Could not detect public IP address using fallback detection service: `$ipAddressDetectServiceFallback`"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# basic safety
|
|
||||||
:set publicIpAddress ([:pick $publicIpAddress 0 15])
|
:set publicIpAddress ([:pick $publicIpAddress 0 15])
|
||||||
|
|
||||||
:if ($detectPublicIpAddress = true) do={
|
:if ($detectPublicIpAddress = true) do={
|
||||||
|
# truncate IP to max 15 characters (basic safety)
|
||||||
:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nPublic IP address: $publicIpAddress")
|
:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nPublic IP address: $publicIpAddress")
|
||||||
:log info "$SMP Public IP address detected: `$publicIpAddress`"
|
:log info "$SMP Public IP address detected: `$publicIpAddress`"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
## STEP 1: Create backups, check for new RouterOS, and send email
|
## STEP ONE: Creating backups, checking for new RouterOs version and sending email with backups,
|
||||||
## Steps 2–3 run only if auto-update is enabled and a new version is available
|
## Steps 2 and 3 are fired only if script is set to automatically update device and if a new RouterOs version is available.
|
||||||
:if ($scriptStep = 1) do={
|
:if ($scriptStep = 1) do={
|
||||||
:local routerOsVersionAvailable "0.0.0"
|
:local routerOsVersionAvailable "0.0.0"
|
||||||
:local isNewOsUpdateAvailable false
|
:local isNewOsUpdateAvailable false
|
||||||
|
@ -479,14 +525,14 @@
|
||||||
:local mailPtSubjectBackup ""
|
:local mailPtSubjectBackup ""
|
||||||
:local mailPtBodyBackup ""
|
:local mailPtBodyBackup ""
|
||||||
|
|
||||||
# Checking for new version
|
# Checking for new RouterOS version
|
||||||
:if ($scriptMode = "osupdate" or $scriptMode = "osnotify") do={
|
:if ($scriptMode = "osupdate" or $scriptMode = "osnotify") do={
|
||||||
log info ("$SMP Setting update channel to `$updateChannel`")
|
log info ("$SMP Setting update channel to `$updateChannel`")
|
||||||
/system package update set channel=$updateChannel
|
/system package update set channel=$updateChannel
|
||||||
log info ("$SMP Checking for new RouterOS version. Current installed version is: `$runningOsVersion`")
|
log info ("$SMP Checking for new RouterOS version. Current installed version is: `$runningOsVersion`")
|
||||||
/system package update check-for-updates
|
/system package update check-for-updates
|
||||||
|
|
||||||
# Wait to allow the system to check for updates
|
# Wait for 5 seconds to allow the system to check for updates
|
||||||
:delay 5s;
|
:delay 5s;
|
||||||
|
|
||||||
:local packageUpdateStatus "undefined"
|
:local packageUpdateStatus "undefined"
|
||||||
|
@ -520,7 +566,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Checking if the script needs to install new os version
|
# Checking if the script needs to install new RouterOS version
|
||||||
:if ($scriptMode = "osupdate" and $isNewOsUpdateAvailable = true) do={
|
:if ($scriptMode = "osupdate" and $isNewOsUpdateAvailable = true) do={
|
||||||
:if ($installOnlyPatchUpdates = true) do={
|
:if ($installOnlyPatchUpdates = true) do={
|
||||||
:if ([$FuncIsPatchUpdateOnly $runningOsVersion $routerOsVersionAvailable] = true) do={
|
:if ([$FuncIsPatchUpdateOnly $runningOsVersion $routerOsVersionAvailable] = true) do={
|
||||||
|
@ -568,7 +614,7 @@
|
||||||
:set mailPtSubjectBackup "Backup failed"
|
:set mailPtSubjectBackup "Backup failed"
|
||||||
:set mailPtBodyBackup "The script failed to create backups. Please check device logs for more details."
|
:set mailPtBodyBackup "The script failed to create backups. Please check device logs for more details."
|
||||||
|
|
||||||
:log warning "$SMP Backup creation failed. Update process will be canceled if automatic update is enabled"
|
:log warning "$SMP Failed to create backup files. Update process will be cancelled, if the script is set to update the device."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,19 +624,20 @@
|
||||||
:local mailStep1Subject $mailSubjectPrefix
|
:local mailStep1Subject $mailSubjectPrefix
|
||||||
:local mailStep1Body ""
|
:local mailStep1Body ""
|
||||||
|
|
||||||
# subject
|
# Assemble email subject
|
||||||
:if ($mailSubjectPartAction != "") do={:set mailStep1Subject ($mailStep1Subject . " - " . $mailSubjectPartAction)}
|
:if ($mailSubjectPartAction != "") do={:set mailStep1Subject ($mailStep1Subject . " - " . $mailSubjectPartAction)}
|
||||||
:if ($mailPtSubjectBackup != "") do={:set mailStep1Subject ($mailStep1Subject . " - " . $mailPtSubjectBackup)}
|
:if ($mailPtSubjectBackup != "") do={:set mailStep1Subject ($mailStep1Subject . " - " . $mailPtSubjectBackup)}
|
||||||
# body
|
# Assemble email body
|
||||||
:if ($mailPtBodyAction != "") do={:set mailStep1Body ($mailStep1Body . $mailPtBodyAction . "\n\n")}
|
:if ($mailPtBodyAction != "") do={:set mailStep1Body ($mailStep1Body . $mailPtBodyAction . "\n\n")}
|
||||||
:if ($mailPtBodyBackup != "") do={:set mailStep1Body ($mailStep1Body . $mailPtBodyBackup . "\n\n")}
|
:if ($mailPtBodyBackup != "") do={:set mailStep1Body ($mailStep1Body . $mailPtBodyBackup . "\n\n")}
|
||||||
|
|
||||||
:set mailStep1Body ($mailStep1Body . $mailBodyDeviceInfo . "\n\n" . $mailBodyCopyright)
|
:set mailStep1Body ($mailStep1Body . $mailBodyDeviceInfo . "\n\n" . $mailBodyCopyright)
|
||||||
|
|
||||||
# Send email with backups
|
# Send email with backup files attached
|
||||||
:do {$FuncSendEmailSafe $emailAddress $mailStep1Subject $mailStep1Body $mailAttachments} on-error={
|
:do {$FuncSendEmailSafe $emailAddress $mailStep1Subject $mailStep1Body $mailAttachments} on-error={
|
||||||
:set isOsNeedsToBeUpdated false
|
:set isOsNeedsToBeUpdated false
|
||||||
:log error "$SMP The script will not proceed with the update process, because the email was not sent."
|
:log error "$SMP The script will not proceed with the update process, because the email was not sent."
|
||||||
|
#:error $exitErrorMessage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,7 +661,7 @@
|
||||||
|
|
||||||
/system package update install
|
/system package update install
|
||||||
} on-error={
|
} on-error={
|
||||||
# Failed to install new os version, remove the task
|
# Failed to install new RouterOS version, remove the scheduled task
|
||||||
:do {/system scheduler remove BKPUPD-NEXT-BOOT-TASK} on-error={}
|
:do {/system scheduler remove BKPUPD-NEXT-BOOT-TASK} on-error={}
|
||||||
|
|
||||||
:log error "$SMP Failed to install new RouterOS version. Please check device logs for more details."
|
:log error "$SMP Failed to install new RouterOS version. Please check device logs for more details."
|
||||||
|
@ -622,7 +669,7 @@
|
||||||
:local mailUpdateErrorSubject ($mailSubjectPrefix . " - Update failed")
|
:local mailUpdateErrorSubject ($mailSubjectPrefix . " - Update failed")
|
||||||
:local mailUpdateErrorBody "The script was unable to install new RouterOS version. Please check device logs for more details."
|
:local mailUpdateErrorBody "The script was unable to install new RouterOS version. Please check device logs for more details."
|
||||||
|
|
||||||
# Send email with error
|
# Send email with error message
|
||||||
$FuncSendEmailSafe $emailAddress $mailUpdateErrorSubject $mailUpdateErrorBody ""
|
$FuncSendEmailSafe $emailAddress $mailUpdateErrorSubject $mailUpdateErrorBody ""
|
||||||
|
|
||||||
:error $exitErrorMessage
|
:error $exitErrorMessage
|
||||||
|
@ -630,26 +677,28 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
## STEP 2: (Post-reboot) Upgrade RouterBOARD firmware
|
## STEP TWO: (after first reboot) routerboard firmware upgrade
|
||||||
## Runs only if auto-update is enabled and a new RouterOS version was found
|
## Steps 2 and 3 are fired only if script is set to automatically update device and if new RouterOs is available.
|
||||||
:if ($scriptStep = 2) do={
|
:if ($scriptStep = 2) do={
|
||||||
:log info "$SMP The script is in the second step, updating Routerboard firmware."
|
:log info "$SMP The script is in the second step, updating Routerboard firmware."
|
||||||
|
|
||||||
:log info "$SMP Upgrading routerboard firmware from v.$deviceRbCurrentFw to v.$deviceRbUpgradeFw"
|
:log info "$SMP Upgrading routerboard firmware from v.$deviceRbCurrentFw to v.$deviceRbUpgradeFw"
|
||||||
|
|
||||||
/system routerboard upgrade
|
/system routerboard upgrade
|
||||||
|
## Wait until the upgrade is completed
|
||||||
:delay 2s
|
:delay 2s
|
||||||
|
|
||||||
:log info "$SMP routerboard upgrade process was completed, going to reboot in a moment!";
|
:log info "$SMP routerboard upgrade process was completed, going to reboot in a moment!";
|
||||||
|
|
||||||
## Set task to send final report on the next boot
|
## Set scheduled task to send final report on the next boot, task will be deleted when it is done. (That is why you should keep original script name)
|
||||||
/system scheduler add name=BKPUPD-NEXT-BOOT-TASK on-event=":delay 5s; /system scheduler remove BKPUPD-NEXT-BOOT-TASK; :global buGlobalVarScriptStep 3; :global buGlobalVarTargetOsVersion \"$buGlobalVarTargetOsVersion\"; :delay 10s; /system script run BackupAndUpdate;" start-time=startup interval=0
|
/system scheduler add name=BKPUPD-NEXT-BOOT-TASK on-event=":delay 5s; /system scheduler remove BKPUPD-NEXT-BOOT-TASK; :global buGlobalVarScriptStep 3; :global buGlobalVarTargetOsVersion \"$buGlobalVarTargetOsVersion\"; :delay 10s; /system script run BackupAndUpdate;" start-time=startup interval=0
|
||||||
|
|
||||||
|
## Reboot system to boot with new firmware
|
||||||
/system reboot;
|
/system reboot;
|
||||||
}
|
}
|
||||||
|
|
||||||
## STEP 3: Final report (after second reboot, with delay).
|
## STEP THREE: Last step (after second reboot) sending final report
|
||||||
## Runs only if auto-update is enabled and a new RouterOS version was found.
|
## Steps 2 and 3 are fired only if script is set to automatically update device and if new RouterOs is available.
|
||||||
|
## This step is executed after some delay
|
||||||
:if ($scriptStep = 3) do={
|
:if ($scriptStep = 3) do={
|
||||||
:log info ("$SMP The script is in the third step, sending final report.")
|
:log info ("$SMP The script is in the third step, sending final report.")
|
||||||
|
|
||||||
|
@ -663,19 +712,23 @@
|
||||||
:local mailStep3Body ""
|
:local mailStep3Body ""
|
||||||
|
|
||||||
:if ($targetOsVersion = $runningOsVersion) do={
|
:if ($targetOsVersion = $runningOsVersion) do={
|
||||||
:log info "$SMP Successfully verified new RouterOS version: target: `$targetOsVersion`, current: `$runningOsVersion`"
|
:log info "$SMP The script has successfully verified that the new RouterOS version was installed, target version: `$targetOsVersion`, current version: `$runningOsVersion`"
|
||||||
|
|
||||||
:set mailStep3Subject ($mailStep3Subject . " - Update completed - Backup created")
|
:set mailStep3Subject ($mailStep3Subject . " - Update completed - Backup created")
|
||||||
:set mailStep3Body ($mailStep3Body . "RouterOS and routerboard upgrade process was completed")
|
:set mailStep3Body ($mailStep3Body . "RouterOS and routerboard upgrade process was completed")
|
||||||
:set mailStep3Body ($mailStep3Body . "\nNew RouterOS version: v.$targetOsVersion, routerboard firmware: v.$deviceRbCurrentFw")
|
:set mailStep3Body ($mailStep3Body . "\nNew RouterOS version: v.$targetOsVersion, routerboard firmware: v.$deviceRbCurrentFw")
|
||||||
:set mailStep3Body ($mailStep3Body . "\n$changelogUrl\nBackups of the upgraded system are in the attachment of this email.\n\n$mailBodyDeviceInfo\n\n$mailBodyCopyright")
|
:set mailStep3Body ($mailStep3Body . "\n$changelogUrl")
|
||||||
|
:set mailStep3Body ($mailStep3Body . "\nBackups of the upgraded system are in the attachment of this email.")
|
||||||
|
:set mailStep3Body ($mailStep3Body . "\n\n" . $mailBodyDeviceInfo . "\n\n" . $mailBodyCopyright)
|
||||||
|
|
||||||
:set mailAttachments [$FuncCreateBackups $backupNameAfterUpdate $backupPassword $sensitiveDataInConfig];
|
:set mailAttachments [$FuncCreateBackups $backupNameAfterUpdate $backupPassword $sensitiveDataInConfig];
|
||||||
} else={
|
} else={
|
||||||
:log error "$SMP Failed to verify new RouterOS version: target: `$targetOsVersion`, current: `$runningOsVersion`"
|
:log error "$SMP The script was unable to verify that the new RouterOS version was installed, target version: `$targetOsVersion`, current version: `$runningOsVersion`"
|
||||||
:set mailStep3Subject ($mailStep3Subject . " - Update failed")
|
:set mailStep3Subject ($mailStep3Subject . " - Update failed")
|
||||||
|
|
||||||
:set mailStep3Body ($mailStep3Body . "The script was unable to verify that the new RouterOS version was installed, target version: `$targetOsVersion`, current version: `$runningOsVersion`\nCheck device logs for more details.\n\n$mailBodyDeviceInfo\n\n$mailBodyCopyright")
|
:set mailStep3Body ($mailStep3Body . "The script was unable to verify that the new RouterOS version was installed, target version: `$targetOsVersion`, current version: `$runningOsVersion`")
|
||||||
|
:set mailStep3Body ($mailStep3Body . "\nPlease check device logs for more details.")
|
||||||
|
:set mailStep3Body ($mailStep3Body . "\n\n" . $mailBodyDeviceInfo . "\n\n" . $mailBodyCopyright)
|
||||||
}
|
}
|
||||||
|
|
||||||
$FuncSendEmailSafe $emailAddress $mailStep3Subject $mailStep3Body $mailAttachments
|
$FuncSendEmailSafe $emailAddress $mailStep3Subject $mailStep3Body $mailAttachments
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Mikrotik RouterOS automatic backup and update
|
# Mikrotik RouterOS automatic backup and update
|
||||||
|
|
||||||
This script allows you to generate daily backups of MikroTik and send them to an email address. You can also choose to enable automatic RouterOS upgrades or receive notifications exclusively for new firmware versions.
|
This script allows you to generate daily backups of MikroTik and send them to an email address. You can also choose to enable automatic RouterOS upgrades or receive notifications exclusively for new firmware versions.
|
||||||
|
|
||||||
|
|
||||||
> 💡 If you have any ideas about the script or you just want to share your opinion, you are welcome to [Discussions](https://github.com/beeyev/Mikrotik-RouterOS-automatic-backup-and-update/discussions), or you can open an [issue](https://github.com/beeyev/Mikrotik-RouterOS-automatic-backup-and-update/issues) if you found a bug.
|
> 💡 If you have any ideas about the script or you just want to share your opinion, you are welcome to [Discussions](https://github.com/beeyev/Mikrotik-RouterOS-automatic-backup-and-update/discussions), or you can open an [issue](https://github.com/beeyev/Mikrotik-RouterOS-automatic-backup-and-update/issues) if you found a bug.
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,7 +25,7 @@ This script allows you to generate daily backups of MikroTik and send them to an
|
||||||
> Ensure your device identity does not contain spaces and special characters! `System -> Identity`
|
> Ensure your device identity does not contain spaces and special characters! `System -> Identity`
|
||||||
|
|
||||||
##### 1. Configure parameters
|
##### 1. Configure parameters
|
||||||
Take the [script](https://github.com/beeyev/Mikrotik-RouterOS-automatic-backup-and-update/raw/master/BackupAndUpdate.rsc) and configure it's parameters at the beginning of the file.
|
Take the [script](https://github.com/beeyev/Mikrotik-RouterOS-automatic-backup-and-update/raw/master/BackupAndUpdate.rsc) and configure it's parameters at the begining of the file.
|
||||||
This step is straightforward as all parameters are well-commented.
|
This step is straightforward as all parameters are well-commented.
|
||||||
**Important!** Don't forget to provide correct email address for backups and pay attention to `scriptMode` variable.
|
**Important!** Don't forget to provide correct email address for backups and pay attention to `scriptMode` variable.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue