]> Git [git.vados.ru] :: Repos - Mikrotiks/ros.vados.ru.git/commitdiff
Autocommit in repo: ros.vados.ru, generated by owner: root, in 21:10:04 17.08.2026.
authorvados-dev <192440777+vados-dev@users.noreply.github.com>
Mon, 17 Aug 2026 18:10:04 +0000 (21:10 +0300)
committervados-dev <192440777+vados-dev@users.noreply.github.com>
Mon, 17 Aug 2026 18:10:04 +0000 (21:10 +0300)
html/.#AM-Fetch-Generator.rsc [new symlink]
html/AM-Fetch-Generator.rsc [new file with mode: 0644]
html/AM-GlobalFunc.rsc

diff --git a/html/.#AM-Fetch-Generator.rsc b/html/.#AM-Fetch-Generator.rsc
new file mode 120000 (symlink)
index 0000000..af090d6
--- /dev/null
@@ -0,0 +1 @@
+root@amster.3712
\ No newline at end of file
diff --git a/html/AM-Fetch-Generator.rsc b/html/AM-Fetch-Generator.rsc
new file mode 100644 (file)
index 0000000..03034e9
--- /dev/null
@@ -0,0 +1,654 @@
+#!rsc by Vados\r
+# RouterOS script: AM-Backup-UpdateEmail\r
+# Script comment: Update and Backup send notification to EMail\r
+# Copyright (c) 2007-2026 Vados <vados@vados.ru>\r
+#\r
+#\r
+# requires RouterOS, version>=6.43.7\r
+# requires device-mode, fetch\r
+#\r
+# Updated: 15/04/2025\r
+# Website: https://github.com/beeyev\r
+# Notification e-mail (Make sure you have configured Email settings in Tools -> Email)\r
+:local ExitOK false;\r
+:onerror Err {\r
+  :global GlobalConfReady; :global GlobalFuncReady;\r
+  :retry { :if ($GlobalConfReady != true || $GlobalFuncReady != true) \\r
+      do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;\r
+  :local ScriptName [ :jobname ];\r
+\r
+:local IfThenElse do={:if ([ :tostr $1 ] = "true" || [ :tobool $1 ] = true) do={:return $2}; :return $3;}\r
+:local EitherOr do={\r
+  :if ([ :typeof $1 ] = "num") do={:if (($1 != 0) = true) do={:return $1} else={:return $2};}\r
+  :if ([ :typeof $1 ] = "time") do={:if (($1 > 0s) = true) do={:return $1} else={:return $2};}\r
+  :if ([ :len [ :tostr $1 ] ] > 0) do={:return $1} else={:return $2};\r
+}\r
+:local ExitError do={\r
+  :local ExitOK [ :tostr $1 ];\r
+  :local Name   [ :tostr $2 ];\r
+  :local Error  [ :tostr $3 ];\r
+  :if ($ExitOK = "false") do={:log error ($Name [ $IfThenElse ([ :pick $Name 0 1 ] = "\$") \\r
+        "Function" "Script" ] . " '" . $Name . "' exited with error" . \\r
+        [ $IfThenElse (!($Error ~ "^(|true|false)\$")) (": " . $Error) "." ]);}\r
+}\r
+\r
+:global LogPrint;\r
+:global EditSchedulers;\r
+:global DevInfoIncludeIP;\r
+\r
+:local SchedInterval "7d";\r
+:local SchedStartTime "03:41:27";\r
+:local SchedComment "Every 7 Day Check For Update and Backup send notification to EMail.";\r
+\r
+# Function to add or edit schedulers for scripts, to ensure they are set up correctly\r
+# How to use:\r
+# Call this function with the following parameters:\r
+# 1. $1 - Scheduler name (usually same as script name) [*]\r
+# 2. $2 - Interval (e.g. "1d" (default is "1d")) [**]\r
+# 3. $3 - Start Time (e.g. "00:00:00", default is current time) [**]\r
+# 4. $4 - Comment (optional, default: "Scheduler for script: <name>") [**]\r
+# 5. $5 - On Event command (e.g. "/system/script { run <name>; }" (default is "/system/script { run $SchedName; }")) [**]\r
+# 6. $6 - Policy (e.g. "ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon" (default is the same)) [**]\r
+# 7. $7 - Start Date (e.g. "jan/01/1970", default is current date) [**]\r
+# Notes:\r
+# *  - Scheduler name is required, and is used to identify the scheduler to create or edit. It is usually the same as the script name ($ScriptName).\r
+# ** - If optional parameters are not provided, default values will be used.\r
+#      This allows for quick setup with minimal parameters, while still providing flexibility for customization.\r
+# Example usage:\r
+# :if ([ $EditSchedulers "my-script" ] = false) do={:set ExitOK false; :error true;}\r
+# :if ([ $EditSchedulers "my-script" "1d" "03:41:27" "My custom scheduler comment" false false "jan/01/1970" ] = false) do={:set ExitOK false; :error true;}\r
+\r
+:set EditSchedulers do={\r
+  :local SchedName [ :tostr $1 ];\r
+  :if ([ :len $SchedName ] = 0) do={ :return false; }\r
+  :local Interval [ :tostr $2 ];\r
+  :if ([ :len $Interval ] = 0) do={ :set Interval "1d"; }\r
+  :local StartTime [ :tostr $3 ];\r
+  :if ([ :len $StartTime ] = 0) do={ :set StartTime [/system/clock/get time]; }\r
+  :local Comment [ :tostr $4 ];\r
+  :if ([ :len $Comment ] = 0) do={ :set Comment "Scheduler for script: $SchedName"; }\r
+  :local OnEvent [ :tostr $5 ];\r
+  :if ([ :len $OnEvent ] = 0) do={ :set OnEvent "/system/script { run $SchedName; }"; }\r
+  :local Policy [ :tostr $6 ];\r
+  :if ([ :len $Policy ] = 0) do={ :set Policy "ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon"; }\r
+  :local StartDate [ :tostr $7 ];\r
+  :if ([ :len $StartDate ] = 0) do={ :set StartDate [/system/clock/get date]; }\r
+\r
+  :onerror Err {\r
+    # Check if scheduler exists, if not - create it\r
+    :if ([ :len [ /system/scheduler/find where name=$SchedName ] ] = 0) do={\r
+      :log warning ($SchedName . "System Scheduler for script: " . $SchedName . " is NOT SET! Fix It Now!");\r
+      /system/scheduler/add comment=$Comment interval=$Interval name=$SchedName on-event=$OnEvent policy=$Policy start-date=$StartDate start-time=$StartTime;\r
+    }\r
+    # Check if scheduler parameters are correct, if not - fix them\r
+    :if ([ /system/scheduler/get $SchedName comment ] != $Comment) do={\r
+      /system/scheduler/set $SchedName comment=$Comment;\r
+    }\r
+    :if ([ /system/scheduler/get $SchedName interval ] != $Interval) do={\r
+      /system/scheduler/set $SchedName interval=$Interval;\r
+    }\r
+    :if ([ /system/scheduler/get $SchedName on-event ] != $OnEvent) do={\r
+      /system/scheduler/set $SchedName on-event=$OnEvent;\r
+    }\r
+    :if ([ /system/scheduler/get $SchedName policy ] != $Policy) do={\r
+      /system/scheduler/set $SchedName policy=$Policy;\r
+    }\r
+    :if ([ /system/scheduler/get $SchedName start-date ] != $StartDate) do={\r
+      /system/scheduler/set $SchedName start-date=$StartDate;\r
+    }\r
+    :if ([ /system/scheduler/get $SchedName start-time ] != $StartTime) do={\r
+      /system/scheduler/set $SchedName start-time=$StartTime;\r
+    }\r
+  } do={:log error ($SchedName . "Failed to add/modify scheduler for '" . $SchedName . "' failed: " . $Err); :return false};\r
+    :return true;\r
+}\r
+\r
+:if ([ $EditSchedulers $ScriptName $SchedInterval $SchedStartTime $SchedComment ] = false) do={\r
+  :log error ($ScriptName . "Failed to add/modify scheduler for " . $ScriptName . "!");\r
+  :set ExitOK true;\r
+  :error true;\r
+}\r
+\r
+# Local Function CheckOSUpdateMode\r
+:local CheckOSUpdateMode;\r
+:set CheckOSUpdateMode do={\r
+  :local NewMode [ :tostr $1 ];\r
+  :if ([ :len $NewMode ] = 0) do={\r
+    :log error ($0 . "/nFunction /$CheckOSUpdateMode received empty value!");\r
+    :return false;\r
+    :error true;\r
+  }\r
+\r
+  :global BackupAndUpdateMode;\r
+  :global OldMode [ :tostr $BackupAndUpdateMode ];\r
+  :if ($NewMode != $BackupAndUpdateMode && $NewMode = "updateOnce") do={\r
+    :set BackupAndUpdateMode [ :tostr $NewMode ];\r
+    :log info ($0 . "/nOk. /$BackupAndUpdateMode set to: '" . $NewMode . "'.\nYou're a good boy! ))\nI'm launching the update in 5 seconds.");\r
+    :delay 5;\r
+    /system/script { run $ScriptName; };\r
+  } else={\r
+  :log warning ($0 . "/nFunction /$CheckOSUpdateMode received value: '" . $NewMode . "', but is may be only \"updateOnce\"!");\r
+  :return false;\r
+  }\r
+  :return true;\r
+  :error false;\r
+}\r
+\r
+#  :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={\r
+#    $LogPrint warning $ScriptName ("Running from backup partition, refusing to act.");\r
+#    :set ExitOK true;\r
+#    :error false;\r
+#  }\r
+\r
+:global EmailGeneralTo;\r
+:global BackupAndUpdateMode;\r
+:global forceBackup;\r
+:global BackupPassword;\r
+:global BackupSens;\r
+:global updateChannel;\r
+\r
+:global DevInfoIncludeIP;\r
+\r
+# Installs patch updates only (BackupAndUpdateMode = "osupdate").\r
+# Works for `stable` and `long-term` channels.\r
+# Updates only if MAJOR.MINOR match (e.g. 6.43.2 > 6.43.6 allowed, 6.44.1 skipped).\r
+# Sends info if a newer (non-patch) version is found.\r
+:local installOnlyPatchUpdates false;\r
+:local scriptVersion "26.04.30";\r
+:local copyrightUrl "https://www.github.com/vados-dev/";\r
+#Script messages prefix\r
+:local SMP "BkpAndUpdate:";\r
+\r
+:local exitErrorMessage "$SMP script stopped due to an error. Please check logs for more details.";\r
+:log info "\n\n$SMP Script \"Mikrotik RouterOS automatic backup & update\" v.$scriptVersion started.";\r
+:log info "$SMP Script Mode: `$BackupAndUpdateMode`, Update channel: `$updateChannel`, Force backup: `$forceBackup`, Install only patch updates: `$installOnlyPatchUpdates`";\r
+\r
+## vv FUNCTIONS vv ##\r
+:global WaitCheckUpdates; $WaitCheckUpdates;\r
+:global MiniDateTimeStamp;\r
+:local MDTSFix [$MiniDateTimeStamp];\r
+:global Identity;\r
+:global IdentityShort;\r
+:global devBoardName;\r
+:global runningVersion;\r
+:global runningChannel;\r
+:global devModel;\r
+:global devRbSerialNumber;\r
+:global ROsVerAvail;\r
+:global PkgUpdStatus;\r
+\r
+# Checks if two RouterOS version strings differ only by the patch version\r
+# :put [$FuncIsPatchUpdateOnly "6.2.1" "6.2.4"]  # Output: true\r
+# :put [$FuncIsPatchUpdateOnly "6.2.1" "6.3.1"]  # Output: false\r
+:local FuncIsPatchUpdateOnly do={\r
+  :local ver1 $1;\r
+  :local ver2 $2;\r
+  # Extract the major and minor components from a version\r
+  :local extractMajorMinor do={\r
+    :local ver $1;\r
+    :local dot1 [:find $ver "."];\r
+    :if ($dot1 = -1) do={:return $ver}\r
+    :local major [:pick $ver 0 $dot1];\r
+    :local rest [:pick $ver ($dot1 + 1) [:len $ver]];\r
+    :local dot2 [:find $rest "."];\r
+    :local minor $rest;\r
+    :if ($dot2 >= 0) do={:set minor [:pick $rest 0 $dot2]}\r
+    :return ($major . "." . $minor);\r
+  }\r
+\r
+# Compare the major and minor components of both version strings\r
+:if ([$extractMajorMinor $ver1] = [$extractMajorMinor $ver2]) do={:return true}\r
+ :return false;\r
+}\r
+# Creates backups and returns array of names\r
+# Possible arguments:\r
+#  $1 - file name, without extension\r
+#  $2 - password (optional)\r
+#  $3 - sensitive data in config (optional, default: false)\r
+# Example:\r
+#:put [$FuncCreateBackups $backupName]\r
+:local FuncCreateBackups do={\r
+  :local backupName [ :tostr $1 ];\r
+  :local BackPass $2;\r
+  :local BackSens $3;\r
+\r
+  #Script messages prefix\r
+  :local SMP "BkpAndUpdate:";\r
+  :local exitErrorMessage "$SMP script stopped due to an error. Please check logs for more details.";\r
+  :log info ("$SMP global function `FuncCreateBackups` started, input: `$backupName`");\r
+\r
+  # validate required parameter: backupName\r
+  :if ([:typeof $backupName] != "str" or [:len $backupName] = 0) do={\r
+    :log error "$SMP parameter 'backupName' is required and must be a non-empty string";\r
+#    :log warning "$SMP parameter '\$backupName' is required and must be a non-empty string.\nI set '\$backupName' to 'default-backup'";\r
+#    :set $backupName "default-backup";\r
+    :error $exitErrorMessage;\r
+  }\r
+\r
+  :local backupFileSys "$backupName.backup";\r
+  :local backupFileConfig "$backupName.rsc";\r
+  :local backupNames {$backupFileSys;$backupFileConfig};\r
+\r
+  ## Perform system backup\r
+  :if ([:len $BackPass] = 0) do={\r
+    :log info ("$SMP starting backup without password, backup name: `$backupName`");\r
+    /system backup save dont-encrypt=yes name=$backupName;\r
+  } else={\r
+    :log info ("$SMP starting backup with password, backup name: `$backupName`");\r
+    /system backup save password=$BackPass name=$backupName;\r
+  }\r
+  :log info ("$SMP system backup created: `$backupFileSys`");\r
+    ## Export config file\r
+  :if ($BackSens = true) do={\r
+    :log info ("$SMP starting export config with sensitive data, backup name: `$backupName`");\r
+    # Since RouterOS v7 it needs to be explicitly set that we want to export sensitive data\r
+    :if ([:pick [/system resource get version] 0 1] < 7) do={\r
+      :execute "/export compact terse file=$backupName";\r
+    } else={\r
+      :execute "/export compact show-sensitive terse file=$backupName";\r
+    }\r
+  } else={\r
+    :log info ("$SMP starting export config without sensitive data, backup name: `$backupName`");\r
+    /export compact hide-sensitive terse file=$backupName;\r
+  }\r
+  :log info ("$SMP Config export complete: `$backupFileConfig`");\r
+  :log info ("$SMP Waiting a little to ensure backup files are written");\r
+  :delay 20;\r
+  :if ([:len [/file find name=$backupFileSys]] > 0) do={\r
+    :log info ("$SMP system backup file successfully saved to the file system: `$backupFileSys`");\r
+  } else={\r
+    :log error ("$SMP system backup was not created, file does not exist: `$backupFileSys`");\r
+    :error $exitErrorMessage;\r
+  }\r
+  :if ([:len [/file find name=$backupFileConfig]] > 0) do={\r
+    :log info ("$SMP config backup file successfully saved to the file system: `$backupFileConfig`");\r
+  } else={\r
+    :log error ("$SMP config backup was not created, file does not exist: `$backupFileConfig`");\r
+    :error $exitErrorMessage;\r
+  }\r
+  :log info ("$SMP global function `FuncCreateBackups` finished. Created backups, system: `$backupFileSys`, config: `$backupFileConfig`")\r
+  :return $backupNames;\r
+}\r
+# Sends an email\r
+# Parameters:\r
+#  $1 - to (email address)\r
+#  $2 - subject\r
+#  $3 - body\r
+#  $4 - file attachments (optional; pass "" if not needed)\r
+#\r
+# Example:\r
+# $FuncSendEmailSafe "admin@domain.com" "Backup Done" "Backup complete." "backup1.backup"\r
+:local FuncSendEmailSafe do={\r
+  :global EmailGeneralTo;\r
+  :local emailSubject $2;\r
+  :local emailBody $3;\r
+  :local emailAttachments $4;\r
+  :local SMP "Bkp&Upd:";\r
+  :local exitErrorMessage "$SMP script stopped due to an error. Please check logs for more details.";\r
+  :log info "$SMP Attempting to send email to `$EmailGeneralTo`";\r
+  # SAFETY: wait for any previously queued email to finish\r
+  :local waitTimeoutPre 60;\r
+  :local waitCounterPre 0;\r
+  :while (([/tool e-mail get last-status] = "resolving-dns" or [/tool e-mail get last-status] = "in-progress")) do={\r
+    :if ($waitCounterPre >= $waitTimeoutPre) do={\r
+      :log error "$SMP Email send aborted: previous send did not complete after $waitTimeoutPre seconds";\r
+      :error $exitErrorMessage;\r
+    }\r
+    :log info "$SMP Waiting for previous email to finish (status: $[/tool e-mail get last-status])...";\r
+    :delay 1; \r
+    :set waitCounterPre ($waitCounterPre + 1);\r
+  }\r
+  # Send the email\r
+  :do {\r
+    /tool e-mail send to=$EmailGeneralTo subject=$emailSubject body=$emailBody file=$emailAttachments;\r
+  } on-error={\r
+    :log error "$SMP Email send command failed to execute. Check logs and verify email settings.";\r
+    :error $exitErrorMessage;\r
+  }\r
+  # Wait for send status to change from "in-progress" / "resolving-dns"\r
+  :local waitTimeout 60;\r
+  :local waitCounter 0;\r
+  :local emailStatus "";\r
+  :log info "$SMP Waiting for email to be sent, timeout in `$waitTimeout` seconds...";\r
+  :while ($waitCounter < $waitTimeout) do={\r
+    :set emailStatus [/tool e-mail get last-status];\r
+    :if ($emailStatus != "in-progress" and $emailStatus != "resolving-dns") do={\r
+      :log info "$SMP Email send status received: $emailStatus";\r
+      # exit loop\r
+      :set waitCounter $waitTimeout;\r
+    } else={:delay 1; :set waitCounter ($waitCounter + 1)}\r
+  }\r
+  # Final decision based on last status\r
+  :if ($emailStatus = "succeeded") do={\r
+    :log info  "$SMP Email successfully sent to `$EmailGeneralTo`";\r
+  } else={\r
+    :log error "$SMP Email failed to send. Status: `$emailStatus`. Check logs for more details and verify email settings.";\r
+    :error $exitErrorMessage;\r
+  }\r
+}\r
+# Global variable to track current update step\r
+# They need to be initialized here first to be available in the script\r
+:global buGlobalVarTargetOsVersion;\r
+:global buGlobalVarScriptStep;\r
+:local scriptStep $buGlobalVarScriptStep;\r
+:do {\r
+  /system/script/environment remove buGlobalVarScriptStep;\r
+} on-error={}\r
+:if ([:len $scriptStep] = 0) do={\r
+  :set scriptStep 1;\r
+}\r
+## ^^ FUNCTIONS ^^ ##\r
+#\r
+# Initial validation\r
+## Check email settings\r
+:if ([:len $EmailGeneralTo] < 3) do={\r
+  :log error ("$SMP Parameter `\$EmailGeneralTo` is not set, or contains invalid value. Script stopped.");\r
+  :error $exitErrorMessage;\r
+}\r
+# Values will be defined later in the script\r
+:local emailServer "";\r
+:local emailFromAddress [/tool e-mail get from];\r
+:log info "$SMP Validating email settings...";\r
+:do {\r
+  :set emailServer [/tool e-mail get server];\r
+} on-error={\r
+  # This is a workaround for the RouterOS v7.12 and older versions\r
+  :set emailServer [/tool e-mail get address];\r
+}\r
+:if ($emailServer = "0.0.0.0") do={\r
+  :log error ("$SMP Email server address is not correct: `$emailServer`, check `Tools -> Email`. Script stopped.");\r
+  :error $exitErrorMessage;\r
+}\r
+:if ([:len $emailFromAddress] < 3) do={\r
+  :log error ("$SMP Email configuration FROM address is not correct: `$emailFromAddress`, check `Tools -> Email`. Script stopped.");\r
+  :error $exitErrorMessage;\r
+}\r
+# Script mode validation\r
+:if ($BackupAndUpdateMode != "backup" and $BackupAndUpdateMode != "osupdate" and $BackupAndUpdateMode != "updateOnce" and $BackupAndUpdateMode != "osnotify") do={\r
+  :log error ("$SMP Script parameter `\$BackupAndUpdateMode` is not set, or contains invalid value: `$BackupAndUpdateMode`. Script stopped.");\r
+  :error $exitErrorMessage;\r
+}\r
+# Update channel validation\r
+:if ($updateChannel != "stable" and $updateChannel != "long-term" and $updateChannel != "testing" and $updateChannel != "development") do={\r
+  :log error ("$SMP Script parameter `\$updateChannel` is not set, or contains invalid value: `$updateChannel`. Script stopped.");\r
+  :error $exitErrorMessage;\r
+}\r
+# Verify if script is set to install patch updates and if the update channel is valid\r
+:if (($BackupAndUpdateMode = "osupdate" or $BackupAndUpdateMode = "updateOnce") and $installOnlyPatchUpdates = true) do={\r
+  :if ($updateChannel != "stable" and $updateChannel != "long-term") do={\r
+    :log error ("$SMP Patch-only updates enabled, but update channel `$updateChannel` is invalid. Only `stable` and `long-term` are supported. Script stopped");\r
+    :error $exitErrorMessage;\r
+  }\r
+  \r
+  :if ($runningChannel != "stable" and $runningChannel != "long-term") do={\r
+    :log error ("$SMP Script is set to install only patch updates, but the installed RouterOS version is not from `stable` or `long-term` channel: `$runningChannel`. Script stopped");\r
+    :error $exitErrorMessage;\r
+  }\r
+}\r
+#\r
+\r
+:local rawTime [/system clock get time];\r
+:local rawDate [/system clock get date];\r
+\r
+:local deviceOsVerAndChannelRunning [/system/resource/get version];\r
+\r
+:local backupNameTemplate     ("backup_v" . $runningVersion . "_" . $runningChannel . "_" . $MDTSFix);\r
+:local backupNameBeforeUpdate ($backupNameTemplate . "_before_update");\r
+:local backupNameAfterUpdate  ($backupNameTemplate . "_after_update");\r
+\r
+## Email body template\r
+:local mailSubjectPrefix  "$SMP Device - `$IdentityShort`";\r
+:local mailBodyCopyright  "Mikrotik RouterOS automatic backup & update (ver. $scriptVersion) \n$copyrightUrl";\r
+:local changelogUrl     "Check RouterOS changelog: https://mikrotik.com/download/changelogs/";\r
+:local mailBodyDeviceInfo  "";\r
+:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "Device information:");\r
+:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\n---------------------");\r
+:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nName: $Identity");\r
+:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nModel: $devModel");\r
+:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nBoard: $devBoardName");\r
+:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nSerial number: $devRbSerialNumber");\r
+:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nRouterOS version: v$deviceOsVerAndChannelRunning");\r
+:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nBuild time: $[/system/resource/get build-time]");\r
+:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nRouterboard FW Available: $ROsVerAvail");\r
+:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nDevice date-time: $rawDate $rawTime ($[/system/clock/get time-zone-name ])");\r
+:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nUptime: $[/system/resource/get uptime]");\r
+## IP address detection\r
+:if ([ $DevInfoIncludeIP ] = true) do={\r
+  :global GetPubIp;\r
+  :local PublicIpAddress [ $GetPubIp ];\r
+  :set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nPublic IP address: " . $PublicIpAddress . ".");\r
+  :log info "$SMP Public IP address detected: $PublicIpAddress";\r
+}  \r
+\r
+:local mailAttachments  [:toarray ""];\r
+:if ($scriptStep = 1 or $scriptStep = 3) do={\r
+  :if ($scriptStep = 3) do={\r
+    :log info ("$SMP Waiting for one minute before continuing to the final step.");\r
+    :delay 1m;\r
+  }\r
+}\r
+\r
+## STEP 1: Create backups, check for new RouterOS, and send email\r
+## Steps 2รข3 run only if auto-update is enabled and a new version is available\r
+:if ($scriptStep = 1) do={\r
+  :global BackupPassword;\r
+  :global BackupSens;\r
+  :local isNewOsUpdateAvailable false;\r
+  :local isLatestOsAlreadyInstalled true;\r
+  :local isOsNeedsToBeUpdated false;\r
+  :local isUpdateCheckSucceeded false;\r
+  :local isEmailNeedsToBeSent false;\r
+  :local mailSubjectPartAction "";\r
+  :local mailPtBodyAction "";\r
+  :local mailPtSubjectBackup "";\r
+  :local mailPtBodyBackup "";\r
+  # Checking for new version\r
+  :if ($BackupAndUpdateMode = "osupdate" or $BackupAndUpdateMode = "osnotify" or $BackupAndUpdateMode = "updateOnce") do={\r
+    :log info ("$SMP Setting update channel to `$updateChannel`");\r
+     /system/package/update/set channel=$updateChannel;\r
+    :log info ("$SMP Checking for new RouterOS version. Current installed version is: `$runningVersion`");\r
+      $LogPrint debug $ScriptName ("Checking for updates...");\r
+      \r
+#     /system/package/update/check-for-updates without-paging as-value;\r
+#     /system/package/update check-for-updates;\r
+    :delay 5s;\r
+    :set PkgUpdStatus [ /system/package/update/get status ];\r
+    :if ($PkgUpdStatus = "New version is available") do={\r
+    :set ROsVerAvail [/system/package/update/get latest-version];\r
+    }\r
+\r
+    :if ($PkgUpdStatus = "New version is available") do={\r
+      :log info ("$SMP New RouterOS version is available: `$ROsVerAvail`");\r
+      :set isNewOsUpdateAvailable true;\r
+      :set isLatestOsAlreadyInstalled false;\r
+      :set isUpdateCheckSucceeded true;\r
+      :set isEmailNeedsToBeSent true;\r
+      :set mailSubjectPartAction "New RouterOS available";\r
+      :set mailPtBodyAction  "New RouterOS version is available, current version: v$runningVersion, new version: v$ROsVerAvail. \n$changelogUrl";\r
+    } else={\r
+      :if ($PkgUpdStatus = "System is already up to date") do={\r
+        :log info ("$SMP No new RouterOS version is available, the latest version is already installed: `v$runningVersion`");\r
+        :set isUpdateCheckSucceeded true;\r
+        :set mailSubjectPartAction "No os update available";\r
+        :set mailPtBodyAction  "No new RouterOS version is available, the latest version is already installed: `v$runningVersion`";\r
+      } else={\r
+        :log error ("$SMP Failed to check for new RouterOS version. Package check status: `$PkgUpdStatus`");\r
+        :set isEmailNeedsToBeSent true;\r
+        :set mailSubjectPartAction "Error unable to check new os version";\r
+        :set mailPtBodyAction  "An error occurred while checking for a new RouterOS version.\nStatus returned: `$PkgUpdStatus`\n\nPlease review the logs on the device for more details and verify internet connectivity.";\r
+      }\r
+    }\r
+  }\r
+  # Checking if the script needs to install new os version\r
+  :if (($BackupAndUpdateMode = "osupdate" or $BackupAndUpdateMode = "updateOnce") and $isNewOsUpdateAvailable = true) do={\r
+    :if ($installOnlyPatchUpdates = true) do={\r
+      :if ([$FuncIsPatchUpdateOnly $runningVersion $ROsVerAvail] = true) do={\r
+        :log info "$SMP New RouterOS version is available, and it is a patch update. Current version: v$runningVersion, new version: v$ROsVerAvail";\r
+        :set isOsNeedsToBeUpdated true;\r
+      } else={\r
+        :log info "$SMP The script will not install this update, because it is not a patch update. Current version: v$runningVersion, new version: v$ROsVerAvail";\r
+        :set mailPtBodyAction ($mailPtBodyAction . "\nThis update will not be installed, because the script is set to install only patch updates.");\r
+      }\r
+    } else={\r
+      :set isOsNeedsToBeUpdated true;\r
+      }\r
+  }\r
+  # Checking If the script needs to create a backup\r
+  :if ($forceBackup = true or $BackupAndUpdateMode = "backup" or $isOsNeedsToBeUpdated = true) do={\r
+    :log info ("$SMP Starting backup process.");\r
+    :set isEmailNeedsToBeSent true;\r
+    :local backupName $backupNameTemplate;\r
+    # This means it's the first step where we create a backup before the update process\r
+    :if ($isOsNeedsToBeUpdated = true) do={\r
+      :set backupName $backupNameBeforeUpdate;\r
+      #Email body if the purpose of the script is to update the device\r
+      :set mailSubjectPartAction "Update preparation";\r
+      :set mailPtBodyAction ($mailPtBodyAction . "\nThe update process for device '$Identity' is scheduled to upgrade RouterOS from version v.$runningVersion to version v.$ROsVerAvail (Update channel: $updateChannel)");\r
+      :set mailPtBodyAction ($mailPtBodyAction . "\nPlease note: The update will proceed only after a successful backup.");\r
+      :set mailPtBodyAction ($mailPtBodyAction . "\nA final report with detailed information will be sent once the update process is completed.");\r
+      :set mailPtBodyAction ($mailPtBodyAction . "\nIf you do not receive a second email within the next 10 minutes, there may be an issue. Please check your device logs for further information.");\r
+    }\r
+    :do {\r
+      :set mailAttachments [$FuncCreateBackups $backupName $BackupPassword $BackupSens];\r
+      :set mailPtSubjectBackup "Backup created";\r
+      :set mailPtBodyBackup "System backups have been successfully created and attached to this email.";\r
+    } on-error={\r
+      :set isOsNeedsToBeUpdated false;\r
+      :set mailPtSubjectBackup "Backup failed";\r
+      :set mailPtBodyBackup "The script failed to create backups. Please check device logs for more details.";\r
+      :log warning "$SMP Backup creation failed. Update process will be canceled if automatic update is enabled";\r
+    }\r
+  }\r
+  :if ($isEmailNeedsToBeSent = true) do={\r
+    :log info "$SMP Preparing to send email...";\r
+    :local mailStep1Subject $mailSubjectPrefix;\r
+    :local mailStep1Body  "";\r
+    # subject\r
+    :if ($mailSubjectPartAction != "")  do={:set mailStep1Subject ($mailStep1Subject . " - " . $mailSubjectPartAction)}\r
+    :if ($mailPtSubjectBackup != "")  do={:set mailStep1Subject ($mailStep1Subject . " - " . $mailPtSubjectBackup)}\r
+    # body\r
+    :if ($mailPtBodyAction != "") do={:set mailStep1Body ($mailStep1Body . $mailPtBodyAction . "\n\n")}\r
+    :if ($mailPtBodyBackup != "") do={:set mailStep1Body ($mailStep1Body . $mailPtBodyBackup . "\n\n")}\r
+    :set mailStep1Body ($mailStep1Body . $mailBodyDeviceInfo . "\n__________\n" . $mailBodyCopyright);\r
+    :set mailStep1Body ($mailStep1Body . "\n[*** TEST START ***]\n\$DeviceInfo: " . [ $DeviceInfo ] . "\n[*** TEST END ***]\n");\r
+    # Send email with backups\r
+    :do {$FuncSendEmailSafe $EmailGeneralTo $mailStep1Subject $mailStep1Body $mailAttachments} on-error={\r
+      :set isOsNeedsToBeUpdated false;\r
+      :log error "$SMP The script will not proceed with the update process, because the email was not sent.";\r
+    }\r
+  }\r
+  :if ([:len $mailAttachments] > 0) do={\r
+    :log info "$SMP Cleaning up backup files from the file system...";\r
+    /file remove $mailAttachments;\r
+    :delay 2s;\r
+  }\r
+  :if ($isOsNeedsToBeUpdated = true) do={\r
+    :global OldMode;\r
+    :log info "$SMP everything is ready to install new RouterOS, going to start the update process and reboot the device.";\r
+    :do {\r
+      :local nextStep 2;\r
+      :if ($isCloudHostedRouter = true) do={\r
+        :log info "$SMP The device is a cloud hosted router, the second step updating the Routerboard firmware will be skipped.";\r
+        :set nextStep 3;\r
+      }\r
+      :local scheduledCommand (":delay 5s; /system/scheduler remove BKPUPD-NEXT-BOOT-TASK; \\r
+       :global buGlobalVarScriptStep $nextStep; :global buGlobalVarTargetOsVersion \"$ROsVerAvail\"; \\r
+      :delay 10s; /system/script { run $ScriptName; }");\r
+      /system/scheduler add name=BKPUPD-NEXT-BOOT-TASK on-event=$scheduledCommand start-time=startup interval=0;\r
+      /system/package/update install;\r
+     } on-error={\r
+      # Failed to install new os version, remove the task and variables\r
+      :do {\r
+        /system/scheduler remove BKPUPD-NEXT-BOOT-TASK;\r
+        :set BackupAndUpdateMode $OldMode;\r
+        :delay 2;\r
+        :do {\r
+          :global buGlobalVarTargetOsVersion (a);\r
+        } on-error={\r
+          :set $mailSubjectPrefix ($mailSubjectPrefix . "ERROR Remove global variable \$buGlobalVarTargetOsVersion failed!");\r
+        }\r
+#        :if ([ :len $OldMode ] > 0) do={\r
+#          :do {\r
+#           :global OldMode (a);\r
+#          } on-error={\r
+#            :set $mailSubjectPrefix ($mailSubjectPrefix . " ERROR Remove global variable \$OldMode failed!");\r
+#          }\r
+#        }\r
+      } on-error={\r
+        :log error "$SMP Failed to install new RouterOS version. Please check device logs for more details. \\r
+        \nAnd Failed to remove task and variables! Check it!";\r
+        :set $mailSubjectPrefix ($mailSubjectPrefix . " ERROR Remove task and global variables!");\r
+      }\r
+      :log error "$SMP Failed to install new RouterOS version. Please check device logs for more details.";\r
+      :local mailUpdateErrorSubject ($mailSubjectPrefix . " - Update failed");\r
+      :local mailUpdateErrorBody "The script was unable to install new RouterOS version. Please check device logs for more details.";\r
+      # Send email with error\r
+      $FuncSendEmailSafe $EmailGeneralTo $mailUpdateErrorSubject $mailUpdateErrorBody "";\r
+      :error $exitErrorMessage;\r
+    }\r
+  }\r
+}\r
+## STEP 2: (Post-reboot) Upgrade RouterBOARD firmware\r
+## Runs only if auto-update is enabled and a new RouterOS version was found\r
+:if ($scriptStep = 2) do={\r
+  :log info "$SMP The script is in the second step, updating Routerboard firmware.";\r
+  :log info "$SMP Upgrading routerboard firmware from v.$deviceRbCurrentFw to v.$deviceRbUpgradeFw";\r
+  /system routerboard upgrade;\r
+  :delay 2;\r
+  :log info "$SMP routerboard upgrade process was completed, going to reboot in a moment!";\r
+  ## Set task to send final report on the next boot\r
+  /system scheduler add name=BKPUPD-NEXT-BOOT-TASK on-event=":delay 2; :global buGlobalVarScriptStep 3; \\r
+   :global buGlobalVarTargetOsVersion \"$buGlobalVarTargetOsVersion\"; :delay 10s; /system/script { run $ScriptName; }; \ \r
+   :delay 5s; /system/scheduler remove BKPUPD-NEXT-BOOT-TASK;" start-time=startup interval=0;\r
+   :delay 2;\r
+  /system reboot;\r
+}\r
+\r
+## STEP 3: Final report (after second reboot, with delay).\r
+## Runs only if auto-update is enabled and a new RouterOS version was found.\r
+:if ($scriptStep = 3) do={\r
+  :log info ("$SMP The script is in the third step, sending final report.");\r
+  :local targetOsVersion $buGlobalVarTargetOsVersion;\r
+  :do {\r
+#    /system/script/environment remove [find name="buGlobalVarTargetOsVersion"];\r
+    :global buGlobalVarTargetOsVersion (a);\r
+  } on-error={\r
+    :set $mailSubjectPrefix ($mailSubjectPrefix . " ERROR Remove global variable \$buGlobalVarTargetOsVersion failed!");\r
+  }\r
+\r
+  :if ([ :len $OldMode ] != 0) do={\r
+    :do {\r
+#      /system/script/environment remove [find name="OldMode"];\r
+      :global OldMode (a);\r
+      } on-error={\r
+        :set $mailSubjectPrefix ($mailSubjectPrefix . " ERROR! Remove global variable \$OldMode failed!");\r
+       }\r
+  }\r
+  :if ([:len $targetOsVersion] = 0) do={\r
+    :log warning "$SMP Something is wrong, the script was unable to get the target updated OS version from the global variable.";\r
+  }\r
+  :local mailStep3Subject $mailSubjectPrefix;\r
+  :local mailStep3Body  "";\r
+  :if ($targetOsVersion = $runningVersion) do={\r
+    :log info "$SMP Successfully verified new RouterOS version: target: `$targetOsVersion`, current: `$runningVersion`";\r
+    :set mailStep3Subject ($mailStep3Subject . " - Update completed - Backup created");\r
+    :set mailStep3Body ($mailStep3Body . "RouterOS and routerboard upgrade process was completed");\r
+    :set mailStep3Body ($mailStep3Body . "\nNew RouterOS version: v.$targetOsVersion, routerboard firmware: v.$deviceRbCurrentFw");\r
+    :set mailStep3Body ($mailStep3Body . "\n$changelogUrl\nBackups of the upgraded system are in the attachment of this email.\n\n$mailBodyDeviceInfo\n\n$mailBodyCopyright");\r
+    :set mailAttachments [$FuncCreateBackups $backupNameAfterUpdate $BackupPassword $BackupSens];\r
+  } else={\r
+    :log error "$SMP Failed to verify new RouterOS version: target: `$targetOsVersion`, current: `$runningVersion`";\r
+    :set mailStep3Subject ($mailStep3Subject . " - Update failed");\r
+    :set mailStep3Body ($mailStep3Body . "The script was unable to verify that the new RouterOS version was installed, target version: `$targetOsVersion`, current version: `$runningVersion`\nCheck device logs for more details.\n\n$mailBodyDeviceInfo\n\n$mailBodyCopyright");\r
+  }\r
+  $FuncSendEmailSafe $EmailGeneralTo $mailStep3Subject $mailStep3Body $mailAttachments;\r
+  :if ([:len $mailAttachments] > 0) do={\r
+    :log info "$SMP Cleaning up backup files from the file system...";\r
+    /file remove $mailAttachments;\r
+    :delay 2;\r
+  }\r
+  :log info ("$SMP Final report email sent successfully, and the script has finished.");\r
+}\r
+:log info ("$SMP the script has finished, script step: `$scriptStep` \n\n");\r
+\r
+} do={:global ExitError; $ExitError $ExitOK [ :jobname ] $Err}\r
index 03096ec14aaae4ba4afb1aa6b585ba3885fd1c97..127205b021c0a42dbf5816296dc39c4413f968d9 100644 (file)
@@ -17,9 +17,9 @@
 :global GlobalFuncReady false;
 
 # Git commit id & info, expected configuration version
-:global CommitId "main/9347/e7ec422d";
+:global CommitId "main/9348/4b652655";
 :global CommitTAG "unknown";
-:global CommitInfo "Autocommit in repo: ros.vados.ru, generated by owner: root, in 21:05:02 17.08.2026.";
+:global CommitInfo "Autocommit in repo: ros.vados.ru, generated by owner: root, in 21:10:04 17.08.2026.";
 
 # The variables are received right here.
 :global GlobalConfVersion 140;