Using the ForEach-Object
operator I get a string from the list $allImages
that is not in the hashtable $wImages
. Then I have to delete every file with any extension whose name contains this string in $imagesdir
.
$imagesdir = "C:images"
$allImages | ForEach-Object {
if (-not $wImages.ContainsKey($_)) {
Write-Output $_
}
}
What operators should I use to remove the files instead of Write-Output $_
?
2
Note: I’m working under the assumption the strings represented by the key names in the Hashtable are PARTIAL strings: a key named 2023
should thus match a filename "The Largest Baby Beer Battle in Year 2023 of the Current Calendar.whatever"
# the values are completely irrelevant in this case.
$allImages = @{
String_1 = 'value 1'
String_2 = 'value 3'
ThisIsMyKey = 44
'0' = $true
'by the hoary hoggards of the Vishanti!|!' = $null
}
# This also Escape all the Key names.
# You can obviously combine these steps in one line, but it's better to keep
# them easier to read.
$ArrayFromHash = $allImages.Keys | ForEach-Object { [regex]::Escape($_) }
$StringFromArray = $ArrayFromHash -join '|'
$RegexFilter = ".*($StringFromArray).*"
# result is
# .*(String_1|0|by the hoary hoggards of the Vishanti!|!|ThisIsMyKey|String_2).*
Get-ChildItem -file -LiteralPath $imagesdir |
# this will match and thus send to Remove-Item only the names not matching
# $RegxFilter.
Where-Object -Property BaseName -NotMatch -Value $RegexFilter |
# remove -WhatIf if it's working as intended.
Remove-Item -WhatIf
You’ll want to call the Get-ChildItem
cmdlet to discover the files in $imagesDir
, then use a string comparison operator (the -like
wildcard operator or the -match
regex operator) to determine whether the string is found in the name, and then finally pipe the resulting set of files to Remove-Item
.
Additionally, simplify your code with Where-Object
, a cmdlet designed to filter input objects, so:
... |ForEach-Object { if ($condition){ $_ } }
… becomes:
... |Where-Object { $condition }
Let’s give it a try:
# start by constructing a regex pattern from the list of filter strings
$filterStrings = $allImages |Where-Object { -not $wImages.ContainsKey($_) } |ForEach-Object { [regex]::Escape($_) }
if ($filterStrings) {
$filterPattern = $filterStrings -join '|'
# now let's discover the files in the image directory and filter them using the pattern
$filesToRemove = Get-ChildItem -LiteralPath $imagesDir -File |Where-Object {
$_.BaseName -match $filterPattern
}
}
The synthetic BaseName
property will give you the current file’s name without the extension – if you want to search the full file name, use $_.Name
instead of $_.BaseName
Now that you’ve discovered the files you need to delete, go ahead and invoke Remove-Item
:
$filesToRemove |Remove-Item
4