Hello, I am trying to build a search to identify windows user sessions. The main goal was a list/track of users who do not log off of shared systems at the end of the day. There are more use cases I would like to get like identifying concurrent sessions. I think I am close, but I only get open sessions and some weird durations that are not correct. Any suggestions would be appreciated.
index="main" sourcetype=WinEventLog:Security ((EventCode=4624 AND (Logon_Type=2 OR Logon_Type=3 OR Logon_Type=10 OR Logon_Type=11)) OR EventCode=4634 OR EventCode=4647)
| eval TargetUserName=coalesce(TargetUserName, Account_Name)
| where TargetUserName!="$*" AND TargetUserName!="SYSTEM" AND TargetUserName!="LOCAL SERVICE" AND TargetUserName!="NETWORK SERVICE"
| eval EventType = case(EventCode=4624, "Logon", EventCode=4634 OR EventCode=4647, "Logoff")
| sort 0 TargetUserName host -_time
| streamstats count(eval(EventType="Logoff")) as session_rev by TargetUserName host
| stats earliest(eval(if(EventType="Logon", _time, null()))) as firstLogOnEpoch
latest(eval(if(EventType="Logoff", _time, null()))) as lastLogOffEpoch
min(_time) as SessionStartEpoch
max(_time) as SessionEndEpoch
count(eval(EventType="Logon")) as LogonCount
count(eval(EventType="Logoff")) as LogoffCount
by TargetUserName host session_rev
| eval SessionDurationSec = SessionEndEpoch - SessionStartEpoch
| eval SessionDuration = if(isnull(SessionDurationSec),"N/A", tostring(SessionDurationSec,"duration"))
| eval SessionStart = strftime(SessionStartEpoch,"%Y-%m-%d %H:%M:%S")
| eval SessionEnd = strftime(SessionEndEpoch,"%Y-%m-%d %H:%M:%S")
| eval firstLogOn = if(isnull(firstLogOnEpoch),"", strftime(firstLogOnEpoch,"%Y-%m-%d %H:%M:%S"))
| eval lastLogOff = if(isnull(lastLogOffEpoch),"", strftime(lastLogOffEpoch,"%Y-%m-%d %H:%M:%S"))
| eval IsOpenSession = if(isnull(lastLogOffEpoch), 1, 0)
| eval Notes = case(
IsOpenSession=1, "Open session: No logoff found after this logon",
firstLogOn==SessionStart, "SessionStart is first event in search window: firstLogOn may precede search window", 1==1, "")
| table TargetUserName host firstLogOn lastLogOff SessionStart SessionEnd SessionDuration LogonCount LogoffCount IsOpenSession Notes
| sort -SessionStartEpoch
There are many ways to achieve this with streamstats, but my example goes with sorting in ascending time and calculating duration in the streamstats.
See this example which creates 10 dummy logon/off events for a single user/host (SPL can demo up to 4 by changing the 'random() mod value from 1 to 4 in user/host eval)
| makeresults count=10
| eval EventType=mvindex(split("Logon,Logoff", ","), random() % 2)
| eval TargetUserName="USER".mvindex(split("ABCD", ""), random() % 1)
| eval host="HOST".mvindex(split("ABCD", ""), random() % 1)
| eval _time=_time - random() % 3600
| fields EventType Target* host _time
| sort 0 TargetUserName host _time
| streamstats range(_time) as SessionDurationSec reset_after="("EventType=\"Logoff\"")" by TargetUserName host
| streamstats count(eval(SessionDurationSec=0)) as session by TargetUserName host
| eval SessionStart=if(EventType="Logoff", _time - SessionDurationSec, null())
``` Change this to stats to collapse data ```
| eventstats
max(SessionDurationSec) as SessionDurationSec
min(SessionStart) as SessionStart
count(eval(EventType="Logon")) as LogonCount
min(eval(if(EventType="Logon", _time, null()))) as firstLogOn
max(eval(if(EventType="Logoff", _time, null()))) as lastLogOff
by TargetUserName host session
| eval SessionDuration = if(SessionDurationSec=0,"N/A", tostring(SessionDurationSec,"duration"))
| eval IsOpenSession = if(isnull(lastLogOff), 1, 0)
| eval Notes = case(
IsOpenSession=1, "Open session: No logoff found after this logon",
isnull(firstLogOn), "No prior login state found in search window", 1==1, "")
| foreach SessionStart firstLogOn lastLogOff [ eval <<FIELD>>=if(isnull(<<FIELD>>),null(), strftime(<<FIELD>>,"%F %T")) ]
```| table EventType TargetUserName host firstLogOn lastLogOff SessionStart SessionEnd SessionDuration LogonCount LogoffCount IsOpenSession Notes```I've used an eventstats rather than stats so you can see the effect of the decisions made in the SPL, but you can change that to stats to get rid of the unwanted events.
The example ignores multiple logoff events and treats a logoff with no prior login (since a previous logoff) as a 0 length session.
Hope this helps