For example:
action actual_action process user hostname Time
Event 1: allowed Left alone c:\a\b\d mike host_1 00:00:10
Event 2: blocked Deleted c:\a\b\d mike host_1 00:00:12
In this case, first antivirus detects the infects and then it gets cleaned/deleted/quarantined accordingly. Both the events should have the same process, username, and hostname.
I want to generate a report for those users/hosts which has event 1, but not the event 2.
Basically, to filter out those hosts/users for which anti-virus has not taken any action.
This generates some test data
| makeresults | eval host="host_1", user="mike joe ken", action="allowed blocked", process="a b c"
| makemv user| makemv action | makemv process
| mvexpand user | mvexpand action | mvexpand process
| streamstats count as recno | eval _time = _time + 100*recno
| eval host=if(process="c","host_2",host)
this kills a couple of the "blocked" records so that some are left open
| where recno!=17 AND recno!=10 | sort user _time
And here's the part you wanted.
This uses the transaction command to match the "allowed" and "blocked" records when the other three fields match within a 5 minute period, and select only the transaction records where there is no "blocked" event. You can change the maxspan to whatever length of time is appropriate.
| transaction host user process maxspan=5m
| where duration=0
I used a test of the duration, but you could also use eventcount=1 or any number of other things about the transaction.
Does this give you what you're looking for?
... | stats count(eval(action)="allowed") as evt1 count(eval(action)="blocked") as evt2 by host user | where evt2=0 | fields - evt2