Closed tal-zvon closed 5 months ago
This is what I did:
scripts = api.get_resource("/system/script")
script_to_run = scripts.get(name='your_script')[0]
pprint(script_to_run['source'])
This will print out the contents "source" of whatever script that you name. I use this to verify the script before it is ran.
You should also be able to do:
pprint(script_to_run['last-started'])
This will print the last time that the script was ran.
@InfosecBlake Where's the part that actually runs the script? Seeing the source doesn't help if I can't run it
I believe that you had it correct. I my code I did the following:
api.get_binary_resource('/').call('system/script/run',{"number": script_to_run["name"].encode("utf-8")})
I deciced to use "name" instead of "id" due to Mikrotik changing the value of "id" every time a script is ran. This worked for me.
I hope this helps!
Sorry it's been a while since I've tried this. Yes, my original post does work - that wasn't the problem. The problem is that there is no obvious way to get the script output after it runs.
Also, the way I ran the script was ridiculously complicated. Is this really the easiest (or only) way to run a script using the API? Why is this not just output = api.run_script('script_name')
? Is someone allergic to simplicity? The way I did it doesn't even appear to be documented anywhere. I don't recall how I even figured it out.
Did you ever figure this out? I am trying to do the same thing...
Brasswyrm,
The following will run the script:
api.get_binary_resource('/').call('system/script/run',{"number": script_to_run["name"].encode("utf-8")})
I've honestly gotten away from this API client because it doesn't seem to be maintained. I made a tool for configuring Mikrotik that uses SSH and SFTP. I found that building my own tool was easier than using the API.
@InfosecBlake
Thanks, I tried to do what I was doing via Paramiko and it was so much easier. After banging my head against it for a couple of days using SSH fixed my issue almost instantly!
@Brasswyrm Paramiko is great, and works like a charm. If you want to run multiple commands in one session, see my project. My config tool pushes all the commands at once, one line at a time.
Paramiko is great, but the API, or at least a properly-maintained, easy-to-use API, clearly has advantages. For example, if you want to list the IP addresses on the mikrotik, with the API, you get a list of dicts (super easy to work with), while SSH/Paramiko will give you a string back that you need to parse. Parsing strings is error-prone. The output generated when running command through SSH is not designed to be parsed by computers - it's designed to be looked at by people, so the developers can change it anytime they feel like, or show some extra warning line in some uncommon situations which will break scripts.
Accidentally closed the issue while writing a comment on my phone. I never found a way to read the output of a script when running it through this API, or a simpler way to run it using the API.
@tal-zvon
Thanks for the insight, I'll definitely keep that in mind. For my particular situation, I am not really using the routers in any sort of "networking" capacity. I am basically just using them as a 60GHz source for some personal research. So for me, even if something breaks down the line it should be fine because the script that I am writing does not need to be super robust or anything. But if I were to use these routers for an application where the script needs to be more bulletproof, I totally agree that the API would be better.
@Brasswyrm in your situation, I would definitely suggest using Paramiko, especially since there's no known way to get output from a script using the API. I use Paramiko extensively with mikrotiks in such situations as well.
For anyone reading this, here's a working example (tested on RouterOS v. 7.3.1):
>>> api.get_resource("/system/script").get()[0]['source']
'/put "hello"'
>>> async_response = api.get_binary_resource('/').call('system/script/run', {"number": '0'.encode('utf-8')})
>>> async_response.__dict__
{'command': <routeros_api.sentence.CommandSentence object at 0x73a0f2b3eba0>, 'done_message': {'ret': b'hello'}, 'done': True, 'error': None}
>>> async_response.done_message['ret']
b'hello'
Even after reading the Readme, I can't figure out how to run a Mikrotik script, and get its output.
After some digging, running my script seems to work with this:
Super complicated, but ok. Seems to work.
Unfortunately, the
async_response
, which is of typerouteros_api.api_communicator.base.AsynchronousResponse
, doesn't seem to have any way to retrieve the script output.My script just has a single
/put "hello"
line.If you print
async_response
, it just comes back as[]
. If you try to convert it to a list, it's still an empty list.The fact that the class is called
AsynchronousResponse
implies that it may be a non-blocking operation that returns before the output is ready.dir(async_response)
shows no methods to call that will wait for the output to be ready, and adding/delay 15
to my script makes the call take 15 seconds longer, implying this is a synchronous call.Is there no way to get script output? Am I calling scripts wrong?