Is it possible to run a script on login?

Is there a way to monitor logins to the router and run a script, or send an email?

hi,


yes, system scripts (create the script)
system scheduler (create the scheduler of the script.) Here you can configure a exact time to run the script. If you click in the time, you can select “startup”.

I see that there is a way to run a script on router startup, but I am trying to run a script when someone logs into the router.

When I view the logs, I see when someone logs in:

user admin logged in from 192.168.0.1 via web

Can a script be written that allows you to search the logs over the last X minutes to see if anyone has logged in?

I got it figured out… This script pointed me in the right direction: http://wiki.mikrotik.com/wiki/Manual:Scripting-examples#Detect_new_log_entry

The following script I use in conjunction with the scheduler:

# Script to check for specific new logs and send email alerts
# Tested on RouterOS v5.7+

# container to keep track of the last time stamp detected
:global lastTime;

# find log entries where the message contains "logged in" or "login failure"
:local currentBuf [ :toarray [ /log find message~"logged in" || message~"login failure" ] ] ;
# get number of log entries
:local currentLineCount [ :len $currentBuf ] ;

# if any logs were found, proceed
if ($currentLineCount > 0) do={
# based on number of entries, get time of last entry
	:local currentTime "$[ /log get [ :pick $currentBuf ($currentLineCount -1) ] time ]";

# check currentTime length, if length is 15, log is from a previous day and begins with month/day
	:if ([:len $currentTime] = 15 ) do={
# trim currentTime so we are left only with time xx:xx:xx
		:set currentTime [ :pick $currentTime 7 15 ];
	}
	
# the output for the body of the email, includes time stamp and log message
	:local output "$currentTime $[/log get [ :pick $currentBuf ($currentLineCount-1) ] message ]";
	
# email function
	:local sndEmail [:parse "/tool e-mail send to=email@domain.com subject=\"MikroTik alert $currentTime\" body=\"$output\" tls=yes"];

# beep function
	:local doBeep [:parse ":beep;:delay 150ms;:beep;"];


# if the last time stamp has not been set, length will be 0 (after reboot, etc)
	:if ([:len $lastTime] < 1 ) do={ 
# update lastTime to match currentTime
		:set lastTime $currentTime ; 
# send email and beep
		$sndEmail;
		$doBeep;
# if lastTime has been set, continue
	} else={
# if lastTime does not match time stamp of the latest
		:if ( $lastTime != $currentTime ) do={ 
# update lastTime to match currentTime
			:set lastTime $currentTime ; 
# send email and beep
			$sndEmail;
			$doBeep;
		} 
	}
}

v3 - Updated with a few changes:

  • Added a removeThese array to filter out any unwanted log entries from those found. Double quote additional strings and separate them with commas. If you don’t want any logs filtered, simply declare the variable :local removeThese, or leave double quotes :local removeThese (“”)
  • Optimized the last :if statement block to avoid redundant code
  • Removed the [:parse] functions as they didn’t seem to be working on v6.2
  • Time stamp is now saved in the schedule’s comment field instead of a global variable, necessary for when logs are saved on disk to avoid duplicate alert after a reboot

:local scheduleName “mySchedule”
:local emailAddress “myEmail”
:local startBuf [:toarray [/log find message~“logged in” || message~“login failure”]]
:local removeThese (“telnet”,“whatever string you want”)

:local lastTime [/system scheduler get [find name=“$scheduleName”] comment]

:local currentBuf “”; :set currentBuf [:toarray $currentBuf]

:foreach i in=$startBuf do={
:local toggle 1
:foreach j in=[:toarray $removeThese] do={
:if ([:typeof [:find [/log get $i message] “$j”]] = “num”) do={
:set toggle 0
}
}
:if ($toggle = 1) do={
:set currentBuf ($currentBuf , $i)
}
}

:local currentLineCount [ :len $currentBuf ]

if ($currentLineCount > 0) do={
:local currentTime “$[ /log get [ :pick $currentBuf ($currentLineCount -1) ] time ]”

:if ([:len $currentTime] = 15 ) do={
:set currentTime [ :pick $currentTime 7 15 ]
}

:local output “$currentTime $[/log get [ :pick $currentBuf ($currentLineCount-1) ] message ]”

:if (([:len $lastTime] < 1) || (([:len $lastTime] > 0) && ($lastTime != $currentTime))) do={
/system scheduler set [find name=“$scheduleName”] comment=$currentTime
/tool e-mail send to=“$emailAddress” subject=“MikroTik alert $currentTime” body=“$output”
}
}

Skot, script is very nice and very beneficial! Welll done!

Quick question. Script runs flawlessly on 6.2 as you stated. Any way if you have a free moment you could take a look see and try on 6.13. I can’t get the script to complete outside of 6.2.

It would be much appreciated!

Cheers

:local scheduleName value="mySchedule";
:local emailAddress value="myEmail";
:local startBuf value=[:toarray [/log find where message~"logged in" or message~"login failure"] ];
:local removeThese value=[:toarray ("telnet","whatever string you want")];

:local lastTime value=("".[/system scheduler get [find name=$scheduleName] value-name=comment]);

:local currentBuf value=[:toarray ""];

:foreach i in=$startBuf do={
 :foreach j in=$removeThese do={
  :if ([/log get $i value-name=message] ~ $j) do={ } else={
   :set $currentBuf ($currentBuf,$i);
  };
 };
};

:local currentLineCount value=[:len $currentBuf];
 
if ($currentLineCount > 0) do={

 :local currentTime value=[/log get [:pick $currentBuf ($currentLineCount - 1)] value-name=time];

 :if ([:len $currentTime] = 15) do={
  :set $currentTime value=[:pick $currentTime 7 15];
 };

 :local output value=($currentTime." ".[/log get [:pick $currentBuf ($currentLineCount - 1)] value-name=message]);
    
 :if ( ([:len $lastTime] < 1) or ( ([:len $lastTime] > 0) and ($lastTime != $currentTime) ) ) do={
  /system scheduler set [find where name=$scheduleName] comment=$currentTime;
  /tool e-mail send to=$emailAddress subject=("MikroTik alert ".$currentTime) body=$output;
 }

}

Rex,

You’re the man.

You keep solving my problems I’m going to have to put you on the payroll.

I really appreciate it.

Very thanks!

But remeber I fix only the script with standard syntax, the idea is not mine!

Except for this:

From
:local toggle 1
:foreach j in=[:toarray $removeThese] do={
:if ([:typeof [:find [/log get $i message] “$j”]] = “num”) do={
:set toggle 0
}
}
:if ($toggle = 1) do={
:set currentBuf ($currentBuf , $i)
}To

:foreach j in=$removeThese do={
  :if ([/log get $i value-name=message] ~ $j) do={ } else={
   :set $currentBuf ($currentBuf,$i);
  };
 };

Very true!

Rex, 1 last thing when/if you have a moment.

The script runs good but the $currentTime resolves to Jan, 1 1970 after the script is run.

Any ideas? The time on my Routerboard shows to be current and correct.

I see new version of router os omit date on time if date is the same as actual:

/log> pri
jan/01/2002 02:00:09 system,info router rebooted
jan/01/2002 02:00:20 interface,info ether1 link up (speed 100M, full duplex)
jan/01/2002 02:00:24 dhcp,info dhcp-client on ether1 got IP address 192.168.1.101
19:11:42 system,info,account user admin logged in from 192.168.0.102 via winbox
19:12:34 system,info,account user admin logged in from 192.168.0.102 via telnet


The script must be fixed for this…

I fix the syntax but is like I need to fix how date and time are used…




Also are omitted the year: i try to set time to 21 jul and I obtain this:

/log> pri detail
time=jan/01/2002 02:00:09 topics=system,info message=“router rebooted”
time=jan/01/2002 02:00:20 topics=interface,info message=“ether1 link up (speed 100M, full duplex)”
time=jan/01/2002 02:00:24 topics=dhcp,info message=“dhcp-client on ether1 got IP address 192.168.1.101”
time=jul/11 19:11:42 topics=system,info,account message=“user admin logged in from 192.168.0.102 via winbox”
time=jul/11 19:12:34 topics=system,info,account message=“user admin logged in from 192.168.0.102 via telnet”
time=19:16:05 topics=system,info message=“system time zone settings changed by admin”

I think at this point, the script must be rewrited from scratch…

Thanks,

I wrote a quick script to remove the comment from the schedule so the script will still run and I removed the time from the subject of the email.

It will function for the mean time.

Maybe we can get Skot to update the script as it’s very beneficial.

I appreciate your time today.

I have used search function for you, read this old topic, where I post some script for do what you want.
Rememer to read all!!!

http://forum.mikrotik.com/t/script-send-email-as-user-login-into-routerboard/76788/1

Thanks Rex!

I changed up your suggestions from earlier and have the script functioning as I need considering the time is irrelevant to me.

I’ll definitely take a look at your link though.

I owe you a drink next time I’m in Italy!

I count on it :wink:)

Great script! But why only the last log message is send by e-mail? How to set that script to send all monitored messages from last change?

I don’t know why it didn’t work on 6.13. Just now ran it on 6.20 without any problems. Glad rextended’s edit got it working for you.


This code causes problems when there are multiple removeThese array items. For example, say there are 5 array items, and 1 of them is a match. This code does not add the matching one. But for all of the other ones, it adds this same log entry to the currentBuf array 4 times. My original code prevents this by looping through all items, and if a match is found once, the log entry is ignored. If no matching entries are found, only then is the log entry added.


I was aware of the time format having 2 different formats (00:00:00 and jul/11 00:00:00), and the v3 script checks for these. But I did not know about the other one. I wonder what that’s about? I will update the script to check for this.

This is a good idea. Aside from the benefit of not missing any “inbetween” logs, it also provides more flexibility. If you only want the script to check for new logins, say every 5 minutes, this would return them all.

I will work on a new version to incorporate this.

Are You planning to public taht new script at this topic/forum? It would be great:)