0

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?

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
Moose
  • 751
  • 22
  • 42

1 Answers1

3

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')
}
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
  • To traverse through $archive and exclude all of those paths, do i have to use a ForEach loop and imbibe this method that you shared, or do we have a shorter approach as well ? – Moose Aug 03 '17 at 06:05
  • @RiteshThakur Does the sample code at the bottom of my answer look like it has a `foreach` loop in it? – Ansgar Wiechers Aug 03 '17 at 08:12
  • Requirement has been met, although for learning: For multiple path, is this logical: $_.FullName -notmatch '^C:\\(ProgramFiles|windows)\\(folderfromprogramfiles|system|temp|winsxs)\\'. i.e What if i have to exclude multiple folders apart from 'Windows' ? Can iw rite multiple, $_.FullName -notmatch 'Sample here' commands ? – Moose Aug 03 '17 at 10:43
  • While you can have multple `$_.FullName -notmatch 'expression'` clauses doing so would adversely affect performance (b/c regexp matches are comparatively slow). It's better to make just one regular expression, e.g. `^C:\\(Program Files\\some folder|Windows\\(system|temp|winsxs))\\ `. – Ansgar Wiechers Aug 03 '17 at 10:49