Search code examples
powershellcsvcontains

How to delete all the files from folder where name does not include string listed in CSV using PowerShell


I want to delete all the files from folder where name does not include SKU listed in CSV.

This works if SKU is exact match with the file base, but I also want keep images which include the SKU. For example if SKU is "1-526-2" files with names like "1-526-2_1.jpg" and "1-526-2_2.jpg" should not be deleted. Can you somehow add wildcards around the SKU?

Trying to use this:

$filestokeep = import-csv "C:\Users\exmaple\csv.csv" -Header sku).sku
$files = "C:\users\folder"

$data = Get-ChildItem $files -Recurse |
     Where-Object {$filestokeep  -notcontains $_.basename} |
        Remove-Item -WhatIf

Example CSV:

"SKU"
"1-526-2"
"2-1234"
"1-6435"

Example files in folder:

1-123.jpg
1-123_1.jpg
1-526-2.jpg
1-526-2_1.jpg
1-6435_2.jpg
2-1234.jpg
5-16547-5.jpg

Outcome now is:

"Remove File" on target "C:\Users\folder\1-123.jpg".
"Remove File" on target "C:\Users\folder\1-123_1.jpg".
"Remove File" on target "C:\Users\folder\1-526-2_1.jpg".
"Remove File" on target "C:\Users\folder\1-6435_2.jpg".
"Remove File" on target "C:\Users\folder\5-16547-5.jpg".

Outcome should be:

"Remove File" on target "C:\Users\folder\1-123.jpg".
"Remove File" on target "C:\Users\folder\1-123_1.jpg".
"Remove File" on target "C:\Users\folder\5-16547-5.jpg".

Solution

  • For this, I'd use the regex -match operator:

    $sourceFolder = "C:\users\folder"
    $filestokeep  = (Import-Csv "C:\Users\exmaple\csv.csv" -Header sku).sku
    
    # create a regex string of the filestokeep array combining the
    # strings with regex OR (`|`). Use [regex]::Escape() to escape any characters
    # that have special meaning in regex.
    # in this example "^(1-526-2|2-1234|1-6435)"
    # the "^" anchors the match at the beginning of the string
    $keepThese = '^({0})' -f (($filestokeep | ForEach-Object { [regex]::Escape($_) }) -join '|')
    
    Get-ChildItem -Path $sourceFolder -Filter '*.jpg' -Recurse -File |
         Where-Object {$_.BaseName -notmatch $keepThese} |
            Remove-Item -WhatIf
    

    Output:

    What if: Performing the operation "Remove File" on target "C:\users\folder\1-123.jpg".
    What if: Performing the operation "Remove File" on target "C:\users\folder\1-123_1.jpg".
    What if: Performing the operation "Remove File" on target "C:\users\folder\5-16547-5.jpg".
    

    P.S. the Remove-Item cmdlet does not return any output, so no need to try ans capture it by using $data =