PowerShell to Search Hash Table Values with -notlike or -notmatch - powershell

I'm attempting to search a hash table for keys that have values that are -notlike or -notmatch 'Snagit'. I am able find an exact match with -notcontains.
Data Example:
Name Value
Host1 FireFox,Snagit 7,Chrome
Host2 Internet,Chrome
Host3 Snagit 5,Internet,Stuff
Code Example:
$global:Csv = Import-Csv -LiteralPath $global:ConvertedSNWReport
$global:hash = #{}
Import-Csv -LiteralPath $global:ConvertedSNWReport | ForEach-Object {
$global:hash[$_.'Computer name'] += #($_.Application)
}
$global:Results = $hash.GetEnumerator() | Where-Object {
$_.Value -notmatch '*Snagit*'
}

You can nest your Where-Object statements to accomplish this:
$results = $hash.GetEnumerator() |Where-Object {
-not($_.Value |Where-Object {$_ -like '*snagit*'})
}
If any of the items in the individual value array matches snagit, the expression will evaluate to $false and the hashtable entrt will be skipped. Conversely, if no items match snagit, it will evaluate to $true
As Ansgar just reminded me, the nested Where-Object statement isn't actually necessary when evaluating strings, since -like doubles as a filter operator on collections:
$results = $hash.GetEnumerator() |Where-Object {
-not($_.Value -like '*snagit*')
}

Related

How can do these on one line, I seem to having trouble getting it to work

$NameMatches = $Prices | Where-Object 'name' -EQ $sub.OfferName
$TermMatches = $NameMatches | where-object 'itemCode' -match $Term
$BillingFreqMatches = $TermMatches | where-object 'ItemCode' -match $BillingFreq
These 3 lines work, but any syntax I use to put them on one line returns no results.
Seems like you're looking for this:
$Prices | Where-Object {
$_.Name -eq $sub.OfferName -and $_.itemCode -match $Term -and $_.itemCode -match $BillingFreq
}
Note that you cannot use Comparison Statement when doing multiple conditions, you must use Script block. See Description section from the Cmdlet's MS Docs.

Can I filter 2 different CommandType using Poweshell?

Here is my roadblock, I am creating a filter that will check for wildcards but from 2 different CommandType
Here is my sample filter
($_.PSParentPath -notlike $Exclusion1) -and ($_.Issuer -notlike $Exclusion2)
I want to filter a word from $.PSParentPath and from $.Issuer. Is this possible? IF it is can someone give me some pointers?
Thank you in advance
$Expiry = Get-ChildItem -Path cert: -Recurse
$ExpiryDetails1 = $Expiry | Where-object {
$_.notafter -le (get-date).Adddays($DaysBeforeExpiry) -AND
$_.notafter -gt (get-date) -AND
($_.PSParentPath -notlike $Exclusion1) -AND
($_.PSParentPath -notlike $Exclusion2) -AND
($_.PSParentPath -notlike $Exclusion3) -AND
($_.Issuer -notlike $Exclusion4) -AND
($_.Issuer -notlike $Exclusion5)
} |
Select-Object psparentpath, issuer, subject, notafter |
format-list
So one of the things we can do is expand away from -Like and -NotLike
And use -Match and -NotMatch, this uses Regex to determine if something is $True
Example 1
Lets create a List of Words and Filters then get the results
$Words = "Apple", "Bananas","Cherry","Dog","Phone","Pager","Log"
$Filters = ("A*", "*R*").Replace("\","\\").Replace(".","\.").Replace("*",".") -join "|"
$Words | ?{#($_) -notmatch $Filters}
Results
Dog
Phone
Log
The magic is turning the -Like and -NotLike statement into a Regex one
First in Regex we need escape out characters that have power, The First one is the \ backslash, the \ is the escape char for regex.
Next is the . which is the wildcard for regex so we will \ escape it.
Lastly we will replace * to . and instead of passing a array of [string[]] we will make a singular sting using regex version of -and which is |.
**There are more things that will need to be escaped from regex if you do more advanced searches
So we take an array of filters and turn it into regex
In this example we take A* and *R*
$Filters = ("A*", "*R*").Replace("\","\\").Replace(".","\.").Replace("*",".") -join "|"
This makes $Filters look like
A.|.R.
So lets make a more advanced case and create Objects and Filter by Fields
Example 2
Make 1001 custom objects with 2 properties Item1 and Item2 that are randomly filled from $words and only returns the items that do not have *A* or *R* in them
$Words = "Apple", "Bananas","Cherry","Dog","Phone","Pager","Log"
$Filters = ("A*", "*R*").Replace("\","\\").Replace(".","\.").Replace("*",".") -join "|"
$Items = 0..1000 | %{
New-Object PSObject -Property #{
Item1 = $Words[(Get-Random -Minimum 0 -Maximum $Words.Count)]
Item2 = $Words[(Get-Random -Minimum 0 -Maximum $Words.Count)]
}
}
$Items | ?{$_.Item1 -notmatch $Filters -and $_.Item2 -notmatch $Filters}
That returns
Item1 Item2
----- -----
Phone Phone
Dog Dog
Log Phone
Dog Phone
Log Dog
Log Phone
... ...
Hopefully this helps :)
Have a Great Day!
So Edit Here because you posted your code
Seems what you need is this
$IssuerExclusions = ("*MS-Organization-P2P-Access*", "*Windows Azure CRP Certificate Generator*", "*GlobalSign*").Replace("\","\\").Replace(".","\.").Replace("*",".") -join "|"
$PathExclusions = ("C:\*","D:\*").Replace("\","\\").Replace(".","\.").Replace("*",".") -join "|"
$Expiry = Get-ChildItem -Path cert: -Recurse
$Date = Get-Date
$ExpiryDetails = $Expiry | Where-object {
$_.notafter -le $Date.AddDays($DaysBeforeExpiry) -AND
$_.notafter -gt $Date -AND
$_.PSParentPath -notmatch $PathExclusions -AND
$_.Issuer -notmatch $IssuerExclusions
} |
Select-Object psparentpath, issuer, subject, notafter |
format-list

Get-ChildItem Where-Object -notlike $array - Is there a way to do this?

I have written a script that will recurse a specified folder and do some analysis on the files within it. I need to exclude specified sub-folders in the analysis. This list of exclusions changes dependent on the base folder being analysed. I have the script working using a long pattern like this:
Get-ChildItem -File -Recurse $source_folder |
Where-Object {
$_.FullName -notlike "*\folder_name0\*" -and
$_.FullName -notlike "*\folder_name1\*" -and
$_.FullName -notlike "*\folder_name2\*" -and
$_.FullName -notlike "*\folder_name3\*" -and
$_.FullName -notlike "*\folder_name4\*"
}
but this is not very reusable. I would like to be able to store exception lists in .CSVs and call the exception list I need based on the folder set I am analyzing. What I would like to do is something like:
$exception_list = Import-CSV .\exception_list
Get-ChildItem -File -Recurse $source_folder |
Where-Object {$_.FullName -notlike $exception_list}
but this does not work. I suspect because I can't specify and 'and' or an 'or' between the elements in the array. I did briefly consider trying to create the whole argument on the fly using a foreach($exception in $exception_list){$argument += "$_.FullName -notlike $exception -and"}, but that got silly and complex pretty quickly since you still have to remove the last 'and'.
Is there an efficient way to do this?
this builds an array of partial names to be excluded, and uses that array to build a regex OR for use in a -notmatch test.
$ExcludedDirList = #(
'PSES-'
'vscode'
'Test_'
)
# regex uses the pipe symbol as the logical "OR"
$RegexExcludedDirList = $ExcludedDirList -join '|'
$Results = Get-ChildItem -Path $env:TEMP -File -Recurse |
Where-Object {
$_.DirectoryName -notmatch $RegexExcludedDirList
}
I really like #lee_dailey's pattern of creating the regex. An alternative method could be to use -in or -notin to compare collections.
Using Pester:
It 'Filters correctly' {
$list = #('fileA', 'file1', 'file2', 'file32')
$filter = #('file1', 'file3')
$expected = #('fileA', 'file2', 'file32')
$list | Where-Object { $_ -notin $filter} | should -be $expected
}
Or just plain comparison operators:
$list = #('fileA', 'file1', 'file2', 'file32')
$filter = #('file1', 'file3')
$expected = #('fileA', 'file2', 'file32')
$newlist = $list | Where-Object { $_ -notin $filter}
(Compare-Object $newlist $expected).length -eq 0
> True

How to filter a list with a list of strings in powershell

I have a list of objects and want to filter all elements whose name is like one of the strings in a list.
My current approach is to use where-object, but this results in a long chain of calls to where-object.
Get-AppxPackage |
where-object {$_.name -notlike "*store*"} |
where-object {$_.name -notlike "*MSPaint*"} ...
I would like to reduce the boilerplate needed here as I expect the list of strings to get quite large.
I would further like to be able to use the filter on another output, which seems I am currently only able to do by copy pasting the where-object block.
You can use regex notmatch instead. This will be a lot faster to execute.
Something like
Get-AppxPackage | Where-Object {$_.name -notmatch 'store|MSPaint'}
Instead of typing in the literal names to not match, you can build the pattern from an array or by reading in a textfile.
Lets say you have a list of names in a textfile
store
MSPaint
...
You can then read in this file as array with
$list = Get-Content -Path "<PATH TO THE FILE>"
Next combine this list to build the pattern like
$pattern = (($list | ForEach-Object {[regex]::Escape($_)}) –join "|")
and do
Get-AppxPackage | Where-Object {$_.name -notmatch $pattern}
Hope this helps
this code shows how to filter using -and and -or in the where-object
class cCustomField
{
[string] $Id
[string] $Name
[string] $Description
[string] $Type
[bool] $On_projects
[bool] $On_people
}
$list = New-Object Collections.Generic.List[cCustomField]
... load your data ....
filter using -and -or
$my_object=$list | Where-Object {$_.name -EQ 'gender' -and $_.on_people -EQ $true }

Powershell looking through all columns searching for a keyword

Using powershell, lets say I have a csv file that contains
fname,lname,id,etc..
Is there a way to use where-object to look through all of the columns instead of just one.
For example, instead of doing:
Import-csv location |where-Object {$_.fname -eq "hi"}
next line:
Import-csv location |where-Object {$_.lname -eq "hi"} and so on.
It would be something like:
Import-csv location |where-Object {ANY -eq "hi"}
Yes, you could iterate over $_.psobject.Properties to inspect every column and return $true if one of them matches:
Import-Csv document.csv |Where-Object {
foreach($p in ($_.psobject.Properties |? {$_.MemberType -eq 'NoteProperty'})) {
if($p.Value -match "hi"){ $true }
}
}
Since the column headings / property names are irrelevant and all you care about is the values, you can handle it as text:
Get-Content c:\somedir\somefile.csv |
Where {$_ -like '*"hi"*'}
If you're just after a count, you can just count the matches. If you want objects, you can run the matched lines through convertfrom-csv.