In continuation of the topic, http://forum.mikrotik.com/t/send-sms-from-different-router/148712/1 (where did we manage to figure out how to pass the function) wrote a script transfer function from one router to another. I had to use ftp for transmission, and SSH for placement in the repository and launch. I couldn’t pass the script through a variable. This is a test version, and it works. The bad thing about it is that it is probably not rational: it uses two services and writes to flash, which is bad for Microtics with flash memory. I will be glad if someone points out how to transfer the script in another way, without ftp.
# < SSHtransfer > function of forwarding the SSH client script to the SSH server
# by Sertik 19/01/2023
# use SSH and ftp
# to work, you need to configure the local variables parameters for ftp: fport 21, fuser and fpassword (see below)
# the length of the portable script is limited to 4096 bytes
#
# $1 - address SSH-server
# $2 - port SSH service
# $3 - userName SSH-server
# $4 - name of the source script
# $5 - dst script name
# $6 - "run", if you need to execute the transmitted script immediately
# examples usage:
# :put [$SSHtransfer 192.168.1.2 22 admin sourceScript DstScript]
# :put [$SSHtransfer 192.168.1.2 22 admin sourceScript DstScript run]
:global SSHtransfer do={
# fetch ftp transfer parametrs:
# :local fport 21
# :local fuser admin
# :local fpassword "user`s password"
:if ([:len $1]=0) do={:return "Error IP SSH-Server"}
do {:set $1 [:toip $1]} on-error={:return "Error syntax address IP SSH-Server"}
:if (!any $2) do={:return "Error port"}
do {:set $2 [:tonum $2]} on-error={:return "Error syntax port"}
:if ([:len $3]=0) do={:return "Error username"}
:if ([:len $4]=0) do={:return "Error Source Script name not set"}
:if ([:len $5]=0) do={:return "Error Dst Script name on SSH-server not set"}
:if (([:len $6]>0) && ($6!="run")) do={:return "Error parametr \$6 $6"}
:if ([:len [/system script find name=$4]]=0) do={:return "Error Source Script $4 no find in repository router SSH-client"}
:if ([:len [/system script get $4 source]]>4096) do={:return "Error long source script"}
:global fileContent
:if ([:len [/file find name="transferSSH.txt"]]>0) do={[/file remove transferSSH.txt]}
:delay 1s
/file print file=transferSSH.txt;
do {
:set fileContent [/system script get $4 source]
:delay 3s
:execute script=":put [/system script get \"$4\" source]" file="transferSSH.txt"
} on-error={
[/file remove transferSSH.txt]
:set fileContent
:return "Error script to long"}
:delay 3s
do {
/tool fetch address=$1 port=$fport src-path=transferSSH.txt user=$fuser mode=ftp password=$fpassword dst-path=tSSH.rsc upload=yes
} on-error={:set fileContent; [/file remove transferSSH.txt]; :return "Error ftp transfer script on SSH-server"}
:delay 3s
:set fileContent
[/file remove transferSSH.txt]
:if ($6!="run") do={
:do {
[/system ssh-exec address=$1 port=$2 user=$3 command=":if ([:len [/system script find name=\"$5\"]]>0) do={/system script remove \"$5\"}; \
/system script add name=\"$5\" source=[/file get tSSH.rsc contents]; :delay 2s; /file remove tSSH.rsc"]; \
} on-error={:return "Error add script $5 in SSH-server repository"}
} else={\
:do {
[/system ssh-exec address=$1 port=$2 user=$3 command=":if ([:len [/system script find name=\"$5\"]]>0) do={/system script remove \"$5\"}; \
/system script add name=\"$5\" source=[/file get tSSH.rsc contents]; :delay 3s; /file remove tSSH.rsc; \
:put RUN;\
/system script run \"$5\""]
} on-error={:return "Error add script $5 in SSH-server repository or run"}
:set $6 ("and $6")
}
:return "Done: Script $5 add to SSH-server repository $6"
}
This allows you to overcome the limitation of the length of the transferred script 4Kb and allows you to transfer scripts 63Kb and maybe more, did not check.
But, at the same time, the script is immediately executed, but not added to the repository … That’s a pity …
Thanks ! Very cool ! Your script will definitely come in handy.
But, unfortunately, the REST API only works on ROS7, and I would like to do it universally for both 6 and 7
I dont think there’s any way to interract with routeros machine besides SSH.
Also, translate something like this to .rsc lang likely impossible.
What kind of script you’r going to send btw?
I want to have (write) a universal function that could send any repository scripts. Mine is limited to sending scripts with a length of 4096 bytes. Moreover, it can save a script of any length as a file, it can also transmit any length. When /system script add on the SHH server, a script larger than 4096 bytes is added as an empty script, i.e. the restriction is here. With /import, you can pass scripts of any length, but they are not added to the repository if they themselves do not have the /system script add instruction, and for some reason they are executed immediately, although this is not always necessary.
P/S for Rex… What I’m not happy about in my function:
That it uses two services ssh and ftp. You can, of course, configure both services on the same port, but somehow it seems crooked to me …
with /import, you can transfer a script up to 40 kB, but the script does not fit into the repository, but immediately starts on the fly and disappears into nowhere.
3.I can’t get around the 4096 bytes limit of the passed script without /import
The MAXLENGTH of a script is 30000 characters (\tabulatin \newline \return etc. are included on limit)
The MAXLENGTH of a variable on memory (63K) are sufficent to escape such script.
I can successfully transfer that script by my method.
If more complex script is needed, is better create multiple script and put the functions on that scripts.
Just one idea…
Elaborating that script, is possible to send file with size less than 63K by SSH…
This will be very interesting, but it seems that it is needed to load the file in memory to pass it to ssh-exec.
How do you will overcome the 4K limit?
Hello Rex! This is something great! I haven’t had time to check yet, but since you wrote it, it means it definitely works! I understand from the code that this function first recodes each character of the transmitted script … Is that so? Could you explain the correct algorithm of this function? I will definitely check it and write it. Thanks a lot !
Did you write it like this right off the bat? Or were there some blanks? You are so cool !
Your ASCIItoESCAPE array is especially interesting, it has elements of variable length! I would never write this…
As I understand it, you made the escape function so as not to make a mistake and not miss a single character in the conversion … Great!
Oh… just read the code:
define 2 arrays of same number of items,
on the 1st “ascii”, all possible RouterOS 7-bit ascii + 8th bit (no matter of the codepage, but is CP437)
on the 2nd “ASCIItoESCAPE”, all corresponding escape symbol or same letter / number / character if are equal, like numbers, letter parenthesys, etc.
no matter if the escaped value are more than one character, what count is array position. (for example, also on URL encode space is +, the same size, but ? is %3F, 3 charactes)
at that point read the input string, one character at time
based on character position on “array”, add the same position content on “ASCIItoESCAPE” on the output string.
Done…
Now it remains to make the transfer of the task for the Scheduler.
Something like:
:local RB [/system identity get name]
:local cmdline "/system scheduler add name=("Run script "."$dst"."[/system clock get time]"."[/system clock get date]") start-time=[:totime $6] on-event=\"$source\" interval=[:totime $7] start-date=$5 comment=("added by SSH-exec "."from $RB")];
:put [$sendsched2ssh 192.168.1.2 testsshScheduller "ip2bin" "testScheduller" "Feb/06/2023" "21:06:30" "00:00:00"]
Plus, it is necessary to provide that if interval=00.00.00 (that is, execute once), then the Scheduler task would be added to the text of the Scheduler task after its first (and last) execution:
:set source ("$source".";"."/system scheduler remove name=("Run script "."$dst"."[/system clock get time]"."[/system clock get date]"))
Plus, the added task needs to be wrapped in an error handler
:do { } on error={}
so that if an error occurs during the execution of the task we passed, the script would not stop working and would still be deleted after execution.
I wrote a function module two years ago to add tasks to the Scheduler on a local router. It can be downloaded here (if anyone is interested): https://cloud.mail.ru/public/pLnx/TdU4iEfFN
Unfortunately, the comments there are all in Russian, I did not translate them.
Done, I forget that field because usually the name I do to the script make useless the description, or I put inside the script, on top, the note.
Also the comment can contain special characters, escaped also that.