1

Well i am working on security event log, so when i use -match in the where its good, i have the result waited, but i dont understant if i replace -match by -contains, i have no result.

with this code:

$ip='52.109.12.19'
$id = 5157
Get-WinEvent  -FilterHashtable @{ LogName='security'; id=$id} | 
    Where {$_.Message -match $ip} | 
    select -Property id, message

the result is :

  Id Message                                                                                
  -- -------                                                                                
5157 La plateforme WPF (Windows Filtering Platform) a bloqué une connexion....              
5157 La plateforme WPF (Windows Filtering Platform) a bloqué une connexion....              
5157 La plateforme WPF (Windows Filtering Platform) a bloqué une connexion....              
5157 La plateforme WPF (Windows Filtering Platform) a bloqué une connexion....              
5157 La plateforme WPF (Windows Filtering Platform) a bloqué une connexion....              
5157 La plateforme WPF (Windows Filtering Platform) a bloqué une connexion....              
5157 La plateforme WPF (Windows Filtering Platform) a bloqué une connexion....              
5157 La plateforme WPF (Windows Filtering Platform) a bloqué une connexion....  

with this code:

$ip='52.109.12.19'
$id = 5157
Get-WinEvent  -FilterHashtable @{ LogName='security'; id=$id} | 
    Where {$_.Message -contains $ip} | 
    select -Property id, message

no result

i'd like to understand why i have not the same result .....

Thanks for your help

Frenchy
  • 16,386
  • 3
  • 16
  • 39
  • It's `-contains`, not `-constains`. Also, it should really be: `$ip -contains $_.message`. – Abraham Zinala May 08 '21 at 16:33
  • 1
    `-contains` is a _collection containment_ operator - `$_.Message` is not a collection of objects, it's just a single string, so `$_.Message -contains $something` is functionally the same as `$_.Message -eq $something` – Mathias R. Jessen May 08 '21 at 16:34
  • 1
    @AbrahamZinala sorry just typo, its not the problem – Frenchy May 08 '21 at 16:36
  • 1
    @AbrahamZinala and your second suggestion doesnt work... – Frenchy May 08 '21 at 16:47
  • Closely related, with respect to the misconception about the purpose of `-contains` in PowerShell: https://stackoverflow.com/q/55594661/45375 – mklement0 May 12 '21 at 14:30

2 Answers2

4

Powershell -contains works like JavaScript's Array#includes.

It does not tell you if a string contains a certain substring. It only tells you if an array contains a certain item.

"abc" -contains "a" is $false. "a","b","c" -contains "a" is $true.

If you want to have substring-level "contains", use the -match operator, or the .NET .Contains() method that is available on strings.

Get-WinEvent  -FilterHashtable @{ LogName='security'; id=$id} | 
    Where {$_.Message.Contains($ip)} | 
    select -Property id, message
mklement0
  • 382,024
  • 64
  • 607
  • 775
Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • thanks for the answer, i understand my confusion! – Frenchy May 08 '21 at 16:39
  • @Frenchy Note that `"a" -contains "a"` is `$true`, because PowerShell views the left-hand side as a single-item array, which - incidentally - happens to contain "a". – Tomalak May 08 '21 at 16:40
  • 1
    its ok..i could sleep happy this night!! – Frenchy May 08 '21 at 16:44
  • @Frenchy Oh, and also note that .NET's `.Contains()` is case-sensitive, while PowerShell generally isn't. For IP addresses this doesn't make much of a difference. though. – Tomalak May 08 '21 at 16:48
3

I realize this has already been answered and Tomalak's answer does a great job explaining the differences between -contains & -match. However, and with respect to the code itself -contains, -in, -match & for that matter -eq can be made to work with relative ease.

[EventLogRecord] objects returned by Get-WinEvent include a property aptly named Properties. It's a collection of [EventProperty] objects, the values of which are the replacement strings in the event log message.

Example:

$ip = '52.109.12.19'
$id = 5157
Get-WinEvent -FilterHashtable @{ LogName = 'security'; id = $id} | 
Where-Object { $_.Properties.Value -contains $ip } | 
Select-Object -Property id, message

The above example unrolls the .Value property from the Properties collection and checks if the result contains $ip.

With a little work, you can be more assertive by figuring out which property index holds the value (in this case IP) you're interested in. I usually use something like below to do that:

(Get-WinEvent -FilterHashtable @{ logname = 'Security'; Id = 5157 } | Select-Object -First 1).Properties

This will return a list of properties. Simply count down the list from 0 to the value you're interested in, that's the index number in the Properties collection.

Note: You can also deduce this information from the <EventData>...</EventData> section of the event's XML view in Event Viewer.

For the purposes of the next couple of examples, I'll take an educated guess that the IP you're looking for is at [3]. This is based on Internet research for Windows Platform Filtering event 5157 and is the "Source IP Address" from the event message.

You can use the -eq operator like:

$ip = @('52.109.12.19')
$id  = 5157
Get-WinEvent -FilterHashtable @{ LogName = 'security'; id = $id} | 
Where-Object { $_.Properties.[3].Value -eq $ip } | 
Select-Object -Property id, message

If you declare $ip (or plaural $ips) as an array it might be useful for searching multiple IPs, and you can use the -in operator like below:

$ips = @('52.109.12.19', '52.109.12.20')
$id  = 5157
Get-WinEvent -FilterHashtable @{ LogName = 'security'; id = $id} | 
Where-Object { $_.Properties[3].Value -in $ips } | 
Select-Object -Property id, message

Note: Added an IP to the collection just for demonstration, but this would work even when the array has only 1 element. To a certain extent, this makes the script more flexible.

I haven't performance-tested and/or compared these or other approaches, however, my bet is that the examples thus far will perform better than trying to identify the IP in the larger message text. That may be important if the logs are very large, or, for that matter, there are many logs to search. If it were me, I would probably use something like the 3rd example, using the -in operator.


An aside and although I wouldn't suggest it for this case, you technically could use the -match operator. The key to this is understanding how -match works when its left operand is an array. It will return the elements that match or $null, for example "one","two","three" -match "one", returns one. However, "one","two","three" -match "four", returns nothing. This is usually enough for it to work in a Boolean evaluation.

$ip = @('52.109.12.19')
$id  = 5157
Get-WinEvent -FilterHashtable @{ LogName = 'security'; id = $id} | 
Where-Object { $_.Properties.Value -match $ip } | 
Select-Object -Property id, message

Notice however the right operand is a scalar value. It won't work if it's a collection. Again, I don't recommend this approach but included it for demonstration purposes.

Note: -eq, -like will return similarly when the left operand is a collection. -ne will return those values not equal to the right operand. To learn more about the behavior of comparison operators take a look at about_Comparison_Operators

Steven
  • 6,817
  • 1
  • 14
  • 14
  • Thanks for your precisions, its very helpfull to understand the complexity of some aspects of powershell – Frenchy May 09 '21 at 07:10
  • Nice information nugget there with the `EventProperty` collection, I didn't know that one. – Tomalak May 12 '21 at 14:30