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')
}
Related
I want to use Get-ChildItem Powershell method and pass a list to -Exclude parameter, but I want to use wildcards (like *$exclude* with single string) so that all files that only contain any of the excludes will be excluded. How can I do it?
I want to exclude from Get-ChildItem method return all files that only contain any of the excludes in their names.
I used Contains with a ! (not). You can also use Regex. I also used ALL to get more than one match string. I made the list capital letters and then used ToUpper() to get both lower and uppercase to match. See code below
$excludeList = #("LOG", "CSV")
Get-ChildItem -Path "c:\temp\" `
| where {![Linq.Enumerable]::Any([string[]]$excludeList, [Func[string,bool]]{ param($excludeItem); return $_.Name.ToUpper().Contains($excludeItem) }) -eq $True} `
| ForEach-Object {Write-Host $_.Name}
Using Regex
$excludeList = #("LOG", "CSV")
Get-ChildItem -Path "c:\temp\" `
| where {![Linq.Enumerable]::Any([string[]]$excludeList, [Func[string,bool]]{ param($excludeItem); return $_.Name.ToUpper() -match $excludeItem }) -eq $True} `
| ForEach-Object {Write-Host $_.Name}
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 multiple files stored in folders and subfolders. Almost all of them contain _v1 at the end of the BaseName. I tried the following but I'm getting an error.
Get-ChildItem -Recurse * -Filter "/(_v1)/" |
Rename-Item -NewName { $_.Name -replace '/(_v1)/','' } -WhatIf
Error:
Get-ChildItem : Second path fragment must not be a drive or UNC name.
Try this :
Get-ChildItem "C:\test\ " -recurse -Filter "*_V1*" | % { Rename-Item $_ -NewName $($_.Name -replace "_V1","" ) }
PowerShell isn't Perl. Forward slashes don't indicate a regular expression, they're just literal forward slashes, so neither your filter expression nor your search string will match the intended files. Also, the parentheses (i.e. the capturing group) serve no purpose, so you should remove them.
Use a wildcard pattern as the filter string for Get-ChildItem and apply the regular expression replacement to the basename to avoid unintentional replacements of _v1 elsewhere in the file names.
Get-ChildItem -Filter '*_v1.*' -Recurse |
Rename-Item -NewName { ($_.BaseName -replace '_v1$') + $_.Extension }
If you're running at least PowerShell v3 you can add the parameter -File to Get-ChildItem so that it won't return directories.
This is a follow up question of: PowerShell concatenate output of Get-ChildItem
This code works fine:
Get-ChildItem -Path "D:\Wim\TM1\TI processes" -Filter "*.vue" -Recurse -File |
Where-Object { $_.BaseName -match '^[0-9]+$' } |
ForEach-Object { ($_.FullName -split '\\')[-2,-1] -join '\' } |
Out-File D:\wim.txt
But I would need to restrict the search folder to only certain folders, basically, this filter: D:\Wim\TM1\TI processes\\*}vues (so all subfolders ending in }vues).
If I add that wildcard condition I get no result. Without the restriction, I get the correct result. Is this possible please?
The idea is to get rid of the 3rd line in the first output (which was a copy/paste by me) and also to minimize the number of folders to look at.
You can nest two Get-ChildItem calls:
An outer Get-ChildItem -Directory -Recurse call to filter directories of interest first,
an inner Get-ChildItem -File call that, for each directory found, examines and processes the files of interest.
Get-ChildItem -Path "D:\Wim\TM1\TI processes" -Filter "*}vues" -Recurse -Directory |
ForEach-Object {
Get-ChildItem -LiteralPath $_.FullName -Filter "*.vue" -File |
Where-Object { $_.BaseName -match '^[0-9]+$' } |
ForEach-Object { ($_.FullName -split '\\')[-2,-1] -join '\' }
} | Out-File D:\wim.txt
Note: The assumption is that all *.vue files of interest are located directly in each *}vues folder.
As for what you tried:
Given that you're limiting items being enumerated to files (-File), your directory-name wildcard pattern *}vues never gets to match any directory names and, in the absence of files matching that pattern, returns nothing.
Generally, with -Recurse it is conceptually cleaner not to append the wildcard pattern directly to the -Path argument, so as to better signal that the pattern will be matched in every directory in the subtree.
In your case you would have noticed your attempt to filter doubly, given that you're also using the -Filter parameter.