4

I am trying to use PowerShell's type -wait command to monitor a log file in real time on Windows in the same way that I would use tail -f on Linux, and I want to pipe the file to another command - select-string, like grep - that will trigger an action based on a condition. On Linux, I would use watch to accomplish what I'm trying to do.

In the following example, I am trying to print the phrase "You caught a critter!" whenever a new line, which contains the string "status=Caught", is written to the log file.

while (1) {if (type -wait "$env:USERPROFILE\AppData\Roaming\CritterCatcherApp\Logs\CritterBag-170118.log" | select-string -quiet "state=Caught") {write-host "You caught a critter!"} else {continue}}

Please note that the -quiet argument for the select-string command returns True. Actually, in this example, it only returns True one time, when I first run the command, as the log file has existing lines that contain the string "status=Caught".

I do need to somehow overlook the existing strings (or, e.g., rotate the log files), but right now, the issue is that I need the PowerShell script to not only continue to tail the file, but I also need it to continue to evaluate whether each new line that is written to the file contains the given string. Then, if the string is present, I need to execute an arbitrary action, like print a line; else, continue listening for the string.

The following post indicates that the -wait argument is an option for the Get-Content cmdlet: How to monitor a windows log file in real time? . I am not sure if I should expect -wait to work with a foreach loop, as described in this post: In Powershell can i use the select-string -quiet switch within a foreach statement .

How can I modify the above PowerShell script to tail a log file and execute an action for each new line with a given string, and continue to tail the file and evaluate new lines as they are written?

Community
  • 1
  • 1
Rocky Raccoon
  • 243
  • 3
  • 14

1 Answers1

4

You can do it on the pipeline with Where-Object (?) and ForEach-Object (%):

Get-Content file -wait | ? { $_ -match "status=Caught" } | % { Write-Host "You caught a critter!" }

Each time status=Caught is detected in the file, the Write-Host in the ForEach-Object will execute

arco444
  • 22,002
  • 12
  • 63
  • 67
  • You got it - It works. This is for sure the answer, and at one total line of code, it is an elegant solution. I get the `Write-Host` output a few times due to the existing entries in the file, and solving that will be the next step that I take. Thank you. – Rocky Raccoon Jan 18 '17 at 15:47
  • @RockyRaccoon I know this is old, but have you solved the next step? I.e. skipping lines already present in the file before you start monitoring? – Aleks G Sep 08 '20 at 17:32
  • @AleksG If I recall correctly, I made the `match` criteria more specific, and the log file that I was targeting did rotate each day, with the file name reflecting the current date. So in combination, I was able to avoid any extra lines, if not actually skip them. A quick search turns up the PowerShell `Select-Object` cmdlet, which has a `-Skip` parameter, but I did not use it. I no longer have access to the script, or else I would tell you for certain what I did. If you post a question with your requirements, I will take a look at it. – Rocky Raccoon Sep 09 '20 at 09:43