I am using the following code to get files using include & exclude criteria:
Get-ChildItem -Path Path/To/Folder -Include #("*Basic_TShirt_Men*",) -Exclude #("*black*","*purple*")
The above code filters files whose names contain Basic_TShirt_Men and doesn't contain black or purple. I need to modify the code to search by these criteria:
Criteria 1: Filename includes Basic_TShirt_Men and doesn't contain black or purple OR
Criteria 2: Filename includes Basic_Polo_Shirt and doesn't contain blue OR
Criteria 3: Filename includes Basic_Shirt_Women and doesn't contain pink
How to combine multiple Include/Exclude criteria like above?
Short answer is, you need an extra layer of filtering:
$include = #(
'*Basic_TShirt_Men*'
'*Basic_Polo_Shirt*'
'*Basic_Shirt_Women*'
)
Get-ChildItem Path\To\Folder\* -Include $include |
Where-Object {
$_.Name -like '*Basic_TShirt_Men*' -and $_.Name -notmatch 'black|purple' -or
$_.Name -like '*Basic_Polo_Shirt*' -and $_.Name -notlike '*blue*' -or
$_.Name -like '*Basic_Shirt_Women*' -and $_.Name -notlike '*pink*'
}
Note, the use of the trailing \* after the path should be there for -Include to work properly.
Related
Novice scripter here and I have a script that connects to multiple file servers and recurses through directories on them looking for files over 90 days old. All that works great.
I'm using Get-ChildItem -include and -exclude to filter the files I want to report on but I also need to filter out certain directories and get-childitem can't filter directories so I'm piping the results over to a Where-Object that then compares the $_.FullName property to strings I want to exclude.
My problem is that I'm having to adjust the directory names I'm filtering for on a regular basis depending on what clients name their files and managing the script is getting a little out of hand as I have to keep adding -and ($_.FullName -notMatch "BACKUPS") conditions to the get-childitem line.
Here's my relevant code:
$Exclusions = ('*M.vbk','*W.vbk','*Y.vbk')
$Files = Get-ChildItem $TargetFolder -include ('*.vib','*.vbk','*.vbm','*.vrb') -Exclude $Exclusions -Recurse -File |
Where {($_.LastWriteTime -le $LastWrite) -and
($_.FullName -notMatch "BACKUPS") -and
($_.FullName -notMatch "Justin") -and
($_.FullName -notMatch "Monthly") -and
($_.FullName -notMatch "Template") -and
($_.FullName -notMatch "JIMMY") -and
($_.FullName -notMatch "ISAAC")}
I set up the $Exclusions variable to use in Get-ChildItem so that I have a single variable to adjust as needed. Is there a way to condense all the individual Where ($.FullName -notMatch "JIMMY") entries to just use one variable like... Where ($.FullName -notMatch $DirectoryListVariable)?
Basically I just need to make this easier to manage and change if that's possible. If not then I can just keep adding new lines but I'm hoping there is a better way.
Thanks for your time!
Use regex alternation (|) to match any one of multiple patterns:
# Array of name substrings to exclude.
$namesToExclude = 'BACKUPS', 'Monthly', 'Justin', 'Template', 'JIMMY', 'ISAAC' # , ...
# ...
... | Where-Object {
$_.LastWriteTime -le $LastWrite -and
$_.FullName -notmatch ($namesToExclude -join '|')
}
For case-sensitive matching, use -cnotmatch
As an alternative to defining an array of patterns to then -join with | to form a single string ('BACKUPS|Monthly|...'), you may choose to define your names as part of such a single string to begin with.
Do note that the resulting string must be a valid regex; that is, the individual names are interpreted as regexes (subexpressions) too.
If that is undesired (note that it isn't a problem here, because the specific sample names are also treated literally as regexes), you can escape them with [regex]::Escape().
Finally, note that -match and its variant perform substring (subexpression) matching; to match input strings in full, you need to anchor the expressions, namely with ^ (start of the string) and $ (end of the string); e.g.
'food' -match 'oo' is $true, but 'food' -match '^oo$' is not ('oo' -match '^oo$' is).
I'm iterating through a directory tree but trying to filter out a number of things.
This is my cobbled together code;
Get-ChildItem -Path $pathName -recurse -Filter index.aspx* -Exclude */stocklist/* | ? {$_.fullname -NotMatch "\\\s*_"} | Where {$_.FullName -notlike "*\assets\*" -or $_.FullName -notlike ".bk"}
Remove the name index.aspx from the returned item.
I want to filter out any file that starts with and underscore.
Exclude anything that contains /stocklist/ in its path.
Exclude anything that contains /assets/ in its path.
And exclude anything that contains .bk in its path.
This is working for everything but for the .bk in it's path. I'm pretty sure it's a syntax error on my part.
Thanks in advance.
You can create a regex string and use -notmatch on the file's .DirectoryName property in a Where-Object clause to exclude the files you don't need:
$excludes = '/stocklist/', '/assets/', '.bk'
# create a regex of the folders to exclude
# each folder will be Regex Escaped and joined together with the OR symbol '|'
$notThese = ($excludes | ForEach-Object { [Regex]::Escape($_) }) -join '|'
Get-ChildItem -Path $pathName -Filter 'index.aspx*' -File -Recurse |
Where-Object{ $_.DirectoryName -notmatch $notThese -and $_.Name -notmatch '^\s*_' }
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
I have seen duplicate questions, but nothing worked for me.
I want to exclude looking into certain paths, while performing an operation. This doesn't work:
$archive = ("C:\Windows\Temp*","C:\Windows\winsxs*","C:\Windows\system*")
$final = Get-ChildItem C:\ -Include *.dll -Exclude $archive -Recurse | ? {
$_.PSIsContainer -and $_.FullName -notlike "\\obj\\?"
} | Where-Object {
$_.VersionInfo.LegalCopyright -notmatch 'Microsoft'
}
Please correct me where am I wrong? Do I have to use a foreach loop to iterate through items in $archive and exclude them individually? Pipeline or any other short command is there in this case?
First and foremost, a statement Get-ChildItem -Include *.dll will return only file objects (unless you have a folder named <something>.dll, which would be rather uncommon), so if you filter the output for directory objects ($_.PSIsContainer) you will obviously come up with an empty result. Since the rest of your code suggests that you want files anyway just remove the $_.PSIsContainer clause from your filter.
Also, the -Exclude parameter applies to the name of the items. You can't use it to exclude (partial) paths. If you want files from the given directories omitted from the result you should exclude them in your Where-Object filter with a regular expression match like this:
$_.FullName -notmatch '^C:\\windows\\(system|temp|winsxs)\\'
And finally, wildcard matches (-like, -notlike) require a * wildcard at beginning and/or end of the expression if you want to match a partial string:
PS> 'abcde' -like 'a*e'
True
PS> 'abcde' -like 'c*e'
False
PS> 'abcde' -like '*c*e'
True
Without the leading/trailing * the expression is automatically anchored at beginning/end of the string.
However, your pattern doesn't look like a wildcard expression in the first place. It looks more like a regular expression to me (to match paths containing \obj\ or ending with \obj). For that you'd also use the -notmatch operator:
$_.FullName -notmatch '\\obj\\'
From a perfomance perspective wildcard matches are more efficient, though, so it'd be better to use an expression like this:
$_.FullName -notlike '*\obj\*'
Making the trailing backslash optional is pointless, because Get-ChildItem returns a list of *.dll files, so none of the full paths will end with \obj.
Something like this should do what you want, assuming that I interpreted your code correctly:
$final = Get-ChildItem 'C:\' -Include '*.dll' -Recurse | Where-Object {
$_.FullName -notmatch '^C:\\windows\\(system|temp|winsxs)\\' -and
$_.FullName -notlike '*\obj\*' -and
$_.VersionInfo.LegalCopyright.Contains('Microsoft')
}
I am currently working on a script that will count all of the directories (within a specified path, \\servername\logs\failures) which have a naming convention of "P0*" or "MININT*" - but the folders named as "MININT*" also must have a subfolder that contains a specified log file. Also, it should only be counting folders created in the last 24 hours.
Here is my current code, it keeps returning a zero value and I am not sure why. I have been searching for hours and tried different methods using recurse, Test-Path, etc. to no avail.
$imagefailures = Get-ChildItem '\\servername\logs\failures' -Directory |
Where-Object {
($_.Name -like "P0*") -or
(($_.Name -like "MININT*") -and (Test-Path "\WinPE_TS_X_Win\SMSTSLog\Get-Name.log")) -and
($_.LastWriteTime -gt (Get-Date).AddHours(-24))
} | Measure-Object | select -ExpandProperty Count
Try this:
$imagefailures = Get-ChildItem '\\servername\logs\failures' -Directory |
Where-Object {
($_.Name -like "P0*") -or
(($_.Name -like "MININT*") -and (Test-Path "$($_.FullName)\WinPE_TS_X_Win\SMSTSLog\Get-Name.log")) -and
($_.LastWriteTime -gt (Get-Date).AddHours(-24))`
} | Measure-Object | select -ExpandProperty Count
The path you are testing will always just be "\WinPE_TS_X_Win\SMSTSLog\Get-Name.log" if you do not append it to the folder path you are iterating on.