0

I have been using PS for about 8-9 years. I want to use a SQL table to store a list of values to use in an exclusion WHERE Object clause. The source data is NOT in SQL. It is coming from a data set coming from an Outlook COM object. Basically I want to filter out emails that have certain keywords in the subject. It already has a static list that works just fine, but I would like to give the users the ability to modify this list without updating the code. Here is what I have. It looks like it 'Should' work. In fact, if I render the filter and past it into the WHERE Object, it does work. Just not with the string variable.

$dsExclude = Select-SQL "SELECT Keyword = LTRIM(RTRIM(Keyword)) FROM Email_Mining_Keywords WHERE Action='Exclude' AND WordLocation='Subject'" -ConnectionStringOrSetting $DestConnectionString  


$filter = ($dsExclude | select -ExpandProperty KeyWord | % { "`$_.Subject -NOTlike '*$_*'" }) -join ' -and '
$dsResults |   ?{$filter} | Out-GridView

It took me awhile to figure out that I needed to escape the pipe character from the source dataset while parsing the pipe character from the exclusion dataset. When rendering the filter variable, it looks great & works when manually pasting the filter.

3
  • 1
    what you're looking for is $filter = [scriptblock]::Create($filter) then ? $filter (no {..}). However what you're trying to do is terribly inefficient. You could just build a single regex OR pattern and do ? { $_.Subject -notmatch $bigOrRegexPattern } Commented Jul 23, 2024 at 19:52
  • Pretty sure this was mentioned by someone in the exact same text posted as a different question previously, but your $filter is a non-empty [string], not an executable expression, so your where-object (the ? { ... }) is equivalent to where-object { $true }.
    – mclayton
    Commented Jul 23, 2024 at 19:52
  • Wow, thanks Santiago & mclayton. The [scriptblock]::Create( was what I was missing. Perfect. Thank you. Commented Jul 23, 2024 at 20:06

1 Answer 1

1

The issue with your current approach is that you're evaluating a string in the -FilterScript scriptblock and, unless empty, a string is always true.

'foo' | Where-Object { 'any non empty string is true' }

What you wanted to do instead is to create an expression that is used to filter the collection:

$filter = [scriptblock]::Create(
    $dsExclude.ForEach{ "`$_.Subject -notlike '*$($_.KeyWord)*'" } -join ' -and ')

$dsResults | Where-Object $filter | Out-GridView

This approach is however inefficient and hard to understand, there is a much easier way to approach this problem by creating a regex OR pattern:

# here it is required to escape the value of `KeyWord` to match literally.
# this prevents false positives in case the value could contain special regex characters
$filter = $dsExclude.ForEach{ [regex]::Escape($_.KeyWord) } -join '|'
$dsResults | Where-Object { $_.Subject -notmatch $filter } | Out-GridView
3
  • 1
    Thanks Santiago. I will keep the regex in mind. The data sets are very small<50 rows.with the regex, it removes the need for wildcards, yes? so if the keyword is in the subject it matches and will be excluded, correct? Commented Jul 23, 2024 at 20:30
  • thats correct @KevinAlbrecht, there is no need for wildcards (*) if using the regex approach. much simpler. Commented Jul 23, 2024 at 20:32
  • Great. Thanks for this approach. I have tested it & it is in UAT. Commented Jul 23, 2024 at 20:41

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.