Search code examples
powershell

How to filter in a Powershell Pipe using a blocklist in a extern file like a .txt


I need a Powershellscript that reads all installed Programs, filters them and puts them in a .txt File. I got the basic function but I would like to enhance the script by Filtering out certain Programs using a blocklist. My First try down below works with Variables I have to declare in the script and I dont like that really. The Variables block some Entries with the same start but I want to block more Entries with Random names, I want to use a seperate .txt File as a block list. I allready read to use Get-Content to import the Strings from the File where I get a Array Variable I believe but from there on I dont know ho to proceed, everthing I tried didnt work.

Thats from my Blocklist:

Microsoft Visual C++ Microsoft .NET vs_ Microsoft Windows Desktop Runtime NVIDIA Microsoft ASP.NET Toolkit Documentation
Microsoft TestPlatform SDK Local Feed
Windows System Image Manager on amd64
Windows PE x86 x64 wims
Windows PE x86 x64
Windows Deployment Tools
Windows Deployment Customizations
Kits Configuration Installer
User State Migration Tool
VS Immersive Activate Helper
Microsoft XNA Framework Redistributable 3.1
Microsoft XNA Framework Redistributable 4.0 Refresh

Thats the Code I got so far:

$ignore1="Microsoft Visual C++"; $ignore2="Microsoft .NET"; $ignore3="vs_"; $ignore4="Microsoft Windows Desktop Runtime"; $ignore5="NVIDIA"; $ignore6="Microsoft ASP.NET"
$Outputfile="C:\...\temp\test.txt"
$Filterfile="C:\...\Skripts\Funktionen\blocklist.txt"

$List64 = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*    | Select-Object DisplayName, Publisher, DisplayVersion, InstallDate 
$List32 = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*                | Select-Object DisplayName, Publisher, DisplayVersion, InstallDate
$List = $List64 + $List32
$filters = Get-Content $filterFile

$List | Where-Object DisplayName | 
    Where-Object {($_.DisplayName -notlike "$ignore1*") -and ($_.DisplayName -notlike "$ignore2*") -and ($_.DisplayName -notlike "$ignore3*") -and ($_.DisplayName -notlike "$ignore4*") -and ($_.DisplayName -notlike "$ignore5*") -and ($_.DisplayName -notlike "$ignore6*")} |
     Where-Object DisplayName | Sort-Object -Property Publisher | Format-Table > $Outputfile

Solution

  • As of PowerShell 7.4.x, there is no direct way to match a string against an array of patterns - neither with -match (regexes) nor with -like (wildcard expressions).

    • There's a proposal to introduce such support for -like (and its negated form, -notlike), GitHub issue #2132, but the discussion around it has stalled, unfortunately.

    • Two asides:

      • If you're searching through strings, the Select-String cmdlet does support multiple regex-pattern / literal-substring arguments.

      • Matching entire, literal strings against arrays is already supported, via the -in operator or its operands-reversed variant, -contains.

    For now, your best bet is to construct a single regex that is the equivalent of your multiple -like operations, and to use that with the -notmatch, the negated form of -match, the regular-expression matching operator:

    # Define the list (array) of display-name substrings to ignore.
    # This list could also come from a file, via Get-Content:
    #   $ignoreList = Get-Content $filterFile
    $ignoreList = "Microsoft Visual C++", "Microsoft .NET", "vs_", "Microsoft Windows Desktop Runtime", "NVIDIA", "Microsoft ASP.NET"
    
    # Construct a single regex with alternation (|) from it, escaping
    # each string so that is treated literally during regex matching.
    # The regex is anchored with ^ to ensure that the strings match at the 
    # start of the display names. Given that -match matches *substrings* by
    # default, additional characters, if any, may follow in the display name.
    # In short: ... -match '^foo' is the equivalent of ... -like 'foo*'
    $reIgnore = '^(' + ($ignoreList.ForEach({ [regex]::Escape($_) }) -join '|') + ')'
    
    # ...
    
    # Now you can filter the display names
    # against the regex with the -notmatch operator:
    $List | Where-Object DisplayName | Where-Object DisplayName -notmatch $reIgnore |
      Sort-Object -Property Publisher > $Outputfile