When working on this series of articles, I almost believed that with PowerShell we had a technology that inexplicably came to us from the future. Remember the Star Trek TV series — the original one, of course — when the senior officer of the Enterprise spaceship Spock looked into his visor, scanning the space parsecs? In fact, Spock was looking at the results of the StarShip-approved PowerShell script.
Tricoders? Also work based on PowerShell technology.
Yes, I am a fan of PowerShell technology, and feel free to explore a topic that no blogger has previously considered. For those brought up in the elementary languages ​​of the Linux shell, PowerShell looks like a super-advanced technology. One of the high-tech features of PowerShell, as I mentioned earlier in my note, is the ability to track low-level OS events, such as file updates.
')
Detailed analysis of the Register-WmiEvent requestLet's go back to the wonderful PS code for monitoring files from just one line, which I introduced last time.
1. Register-WmiEvent -Query "SELECT * FROM __InstanceModificationEvent WITHIN 5 WHERE TargetInstance ISA 'CIM_DataFile' and TargetInstance.Path = '\\Users\\bob\\' and targetInstance.Drive = 'C:' and (targetInstance.Extension = 'doc' or targetInstance.Extension = 'txt)' and targetInstance.LastAccessed > '$($cur)' " -sourceIdentifier "Accessor" -Action $action
As you might have guessed, the logic of what is being tracked is contained in the WQL parameter in the Register-WmiEvent query parameter.
As we remember, WQL allows script authors to get general information about Windows system events and, as in our case, about file events — creating, updating, or changing files. Using this query, I easily get information from the dark depths of Windows about file modification events, which are represented as the CIM_DataFile class.
WQL allows you to specify the media and folder in which to search. To do this, use the above properties Drive and Path.
Although I can't use wildcard searches, this is a language feature, not an error — I can instead look for specific file extensions. When developing the script for this note, my goal was to help IT security specialists detect excessive activity related to text files. Therefore, I set a logical condition for searching for files with doc or txt extensions. Is it logical
Now consider one unobvious moment.
I need to collect information about events that occur when someone tries to access the file, including cases where only Microsoft Word documents are read without making changes.
Is it possible to do this?
We all know the Date Modified field, which is available when viewing the list of files in Windows Explorer. But did you know that the “Date of Access” field also exists? Each time you read a Windows file, this field theoretically indicates the current timestamp. You can check this yourself (see below) by clicking on the column headings and turning on the access information field.

However, in practice, Windows computers are usually not configured to update this internal field when the file is opened only for reading and not for modification. Microsoft claims that this reduces performance. But let's discard doubt.
To set up a permanent update of file access time in Windows, use the undervalued fsutil utility program (you will need administrator rights) with the following parameters:
fsutil set behavior disablelastaccess 0
By setting up file access events in my test environment, I also activated reading-only events in Windows.
As a result, I indicated in the above WQL code such a logical search criterion:
targetInstance.LastAccessed > '$($cur)'
It means that I am only interested in file events in which files are accessed after running Register-WmiEvent. The $ cur variable, by the way, is assigned the current time value, which is obtained from the Get-Date cmdlet.
File Access AnalysisWe looked at the WQL language, now let's move on to the remaining Register-WmiEvent parameters.
SourceIdentifer allows you to specify the name of the event. Assigning names to people, striped cats or terriers is recommended, as this allows them to be called when necessary.
And it is suitable for events! There are several cmdlets that require this identifier. For newbies: Unregister-Event is used to remove a given event subscription, Get-Event allows you to view all events that have been queued, Remove-Event is used to remove current events in the queue, and finally, the Wait-Event is used for explicit synchronous waiting . We will use some of these cmdlets in the final code.
I took apart the main components of my script.
It remains to consider the parameter Action. Because Register-WmiEvent responds to events asynchronously, code is required that processes the response to triggering events, and in it, let's say, is the action — in the block of transmitted PowerShell code.
And this leads us to what I’m actually trying to achieve with my script, so I’ll have to reveal my ambitious plans to conquer the entire world of analyzing user behavior with a few lines of PowerShell code.
Here is the plan. This PS script will track the intensity of file access events, compare it with the reference value, and decide whether this intensity falls within a range of uncharacteristic values ​​that may indicate a potential hacking attempt. When this threshold is reached, a great dashboard displays with recent activity data.
In other words, I will have a threat tracking system with an alert that will mark unusual behavior regarding text files in a given directory.
Will Powershell push other security solutions out of the market?No,
Varonis does not need to worry about this for several reasons.
First, tracking events in Windows cannot be called effective. In fact, Microsoft warns that the inclusion of updates about the latest access to the file through fsutil increases the load on the system. In addition, the Register-WmiEvent accelerates the flywheel of internal events: I was confronted with comments stating that cmdlets can slow down the system.
Secondly, I noticed that this monitoring is not performed in real or near real time: there is a delay in receiving file events that reaches 30 minutes or more. At least this was my experience running scripts on my AWS virtual machine. Perhaps on your particular machine, the results will be better, but I don’t think Microsoft can promise anything about this.
Third, no matter how hard I tried, I couldn’t connect the file change event with the user of the application that caused the event. In other words, I know that a file event has occurred, but, unfortunately, it is not possible using Register-WMIEvent to find out who did it.
Therefore, I received a script that can track access to files, but without identification. Hmmm ... let's create a new category of security control called file access analysis that collects data about my actions. Gartner, can you hear me?
Of course, analyzing user behavior is a much more effective way to identify threats, since the actions of specific users are interesting information. My less detailed analysis of file access, although useful, cannot accurately determine abusive behavior because it collects data about the events of several users.
However, for small companies with a small number of registered accounts, analyzing access to files may be sufficient. For example, an administrator can use these scripts if he finds suspicious the behavior of a user who is too often interested in a directory with confidential data. Also this code has some more attractive features.
And even if my script does not complete its work, an even more important argument is to understand the complexity of working with Windows events using PowerShell (or another language you use), which forces you to pay attention to enterprise-class solutions.
Now we are ready to look at the Powershell script block of my Register-WmiEvent cmdlet:
1. $action = { 2. $Global:Count++ 3. $d=(Get-Date).DayofWeek 4. $i= [math]::floor((Get-Date).Hour/8) 5. 6. $Global:cnts[$i]++ 7. 8. #event auditing! 9. 10. $rawtime = $EventArgs.NewEvent.TargetInstance.LastAccessed.Substring(0,12) 11. $filename = $EventArgs.NewEvent.TargetInstance.Name 12. $etime= [datetime]::ParseExact($rawtime,"yyyyMMddHHmm",$null) 13. 14. $msg="$($etime)): Access of file $($filename)" 15. $msg|Out-File C:\Users\bob\Documents\events.log -Append 16. 17. 18. $Global:evarray.Add(@($filename,$etime)) 19. if(!$Global:burst) { 20. $Global:start=$etime 21. $Global:burst=$true 22. } 23. else { 24. if($Global:start.AddMinutes(15) -gt $etime ) { 25. $Global:Count++ 26. #File behavior analytics 27. $sfactor=2*[math]::sqrt( $Global:baseline["$($d)"][$i]) 28. write-host "sfactor: $($sfactor))" 29. if ($Global:Count -gt $Global:baseline["$($d)"][$i] + 2*$sfactor) { 30. 31. 32. "$($etime): Burst of $($Global:Count) accesses"| Out-File C:\Users\bob\Documents\events.log -Append 33. $Global:Count=0 34. $Global:burst =$false 35. New-Event -SourceIdentifier Bursts -MessageData "We're in Trouble" -EventArguments $Global:evarray 36. $Global:evarray= [System.Collections.ArrayList] @(); 37. } 38. } 39. else { $Global:burst =$false; $Global:Count=0; $Global:evarray= [System.Collections.ArrayList] @();} 40. } 41. }
Yes, I check the login using the Out-File cmdlet to create a timestamp entry for each access case. And comparing the number of events with the reference value in the $ Global: baseline array, I find bursts of access to files every 15 minutes.
Here, I fantasized a little and set up a mythical average for the number of events in the reference value for each day of the week, dividing each day into three eight-hour periods. When the peak activity for a given period falls to the far end of the tail of the normal distribution curve, we can assume that a threat has been detected.
File Access Analysis DashboardAfter receiving data on the peak increase in the number of events in $ Global: evarray (opened files with timestamps), I decided that it would be a good idea to display this data as a stylish dashboard. But instead of adding this code to the script block, I “put in the queue” this data in a separate event that can be processed by individual applications.
What?!
Let me explain. This is where the New-Event cmdlet at the end of the above script block comes into play. It simply allows me to send signals asynchronously to another application or script, thus not tying this code to the script block so that the next file access event can be processed.
I will present the full code of my PowerShell script for analyzing file access in the next article. Now I’ll just say that I configured the Wait-Event cmdlet, the only purpose of which is to select these bursts of events and then send them to the output of a beautiful table using Out-GridView.
Here is the final result that will appear in the admin console:

A great solution, considering that the whole “platform” of file access analysis is implemented in 60 lines of PS code.
We reviewed a lot of material, enough for today.
We’ll talk more about the file access analysis script next time, then we’ll go on to look at the excellent features of PowerShell content classification.