Recursive -notmatch in get-childitem with regex

Viewed 257

Recursive -notmatch in get-childitem with regex

I am trying to find some files with set extensions with the following code.

$include = @('*.keystore', '*.cer', '*crt', '*pfx', '*jks', '*.ks')
$exclude = [RegEx]'^C:\\Windows|^C:\\Program Files|^C:\\Documents and Settings|^C:\\Users|\bBackup\b|\bbackup\b|\brelease\b|\breleases\b|\bReleases\b|\bRelease\b'
$trace="trace.txt"
Get-ChildItem "D:\","C:\" -Directory |
  where FullName -notmatch $exclude | ForEach {
  Get-ChildItem -Path $_.FullName -Include $include -Recurse -Force -EA 0| 
  Select-Object -ExpandProperty FullName 
} *>&1 >> $trace

It works but only excludes if the root directory contains one of the patterns. Ex. Excludes D:\Backup but includes D:\something\Backup

Is there a way to exclude the second folder as well?

1 Answers

Try this with a single call to Get-ChildItem and have it look for files. Then in the Where-Objectclause, you filter on the DirectoryName to exclude the folders you don't want in the output.

Also, you can simplify your regex and use it case-insensitively.

Try:

$include = '*.keystore', '*.cer', '*.crt', '*.pfx', '*.jks', '*.ks'
$exclude = '^C:\\(Windows|Program Files|Documents and Settings|Users)|\bBackup\b|\breleases?\b'
$trace   = 'trace.txt'
Get-ChildItem -Path 'C:\','D:\' -File -Include $include -Recurse -Force -ErrorAction SilentlyContinue | 
  Where-Object { $_.DirectoryName -notmatch $exclude } |
  Select-Object -ExpandProperty FullName |
  Set-Content -Path $trace -PassThru

Switch -PassThru makes the result also display on screen


The C:\ drive contains system-defined junction points you do not have access to, even when running as admin.
Based on this answer, you can change the code to:

$include = '*.keystore', '*.cer', '*.crt', '*.pfx', '*.jks', '*.ks'
$exclude = '^C:\\(Windows|Program Files|Documents and Settings|Users)|\bBackup\b|\breleases?\b'
$trace   = 'trace.txt'
Get-ChildItem -Path 'C:\','D:\' -File -Include $include -Force -Recurse -Attributes !Hidden, !System, !ReparsePoint -ErrorAction SilentlyContinue | 
  Where-Object { $_.DirectoryName -notmatch $exclude } |
  Select-Object -ExpandProperty FullName |
  Set-Content -Path $trace -PassThru

As per your comment, here's an example on how you can do this on remote computers, and save the resulting file locally on your computer.

For this demo, I have removed the -Force switch because as you stated you don't need to capture hidden or system files.

$remoteComputers = 'PC01', 'PC01'  # your list of remote machine names here
$trace   = 'trace.csv'             # make your output a CSV file, so you can have the computernam in there as well

$result = Invoke-Command -ComputerName $remoteComputers -ScriptBlock {
    $include = '*.keystore', '*.cer', '*.crt', '*.pfx', '*.jks', '*.ks'
    $exclude = '^C:\\(Windows|Program Files|Documents and Settings|Users)|\bBackup\b|\breleases?\b'
    Get-ChildItem -Path 'C:\','D:\' -File -Include $include -Recurse -ErrorAction SilentlyContinue | 
          Where-Object { $_.DirectoryName -notmatch $exclude } |
          # this time, output an object with the current computername and the file fullname combined
          Select-Object @{Name = 'ComputerName'; Expression = {$env:COMPUTERNAME}}, FullName
}

# save the resulting array of objects in a single CSV file on YOUR local computer
$result | Set-Content -Path $trace -PassThru

You may need to append parameter -Credential to Invoke-Command and feed it admin credentials for the remote machines

Related