Как исключить файлы и папки из Get-ChildItem в PowerShell?

Я сделал сценарий PowerShell, который запускает robocopy с проверками md5.

Он работает нормально, но если я попытаюсь исключить некоторые каталоги или файлы, robocopy обработает исключение, тогда как часть сценария MD5, которая сравнивает хэш, не работает, возвращает некоторые ошибки, потому что у источника больше файлов / хешей, чем у места назначения...

Я перепробовал, может быть, все методы, которые нашел здесь и в Интернете! Я не могу исключить каталоги и / или файлы из пути!

Ниже то, что я сделал до сих пор. В этом режиме работает md5-copy (без исключений):

$Source = "F:\"

$IgnoreDir = @(
    $Source + '$RECYCLE.BIN'
    $Source + "System Volume Information"
    $Source + "VMs"
)   
$IgnoreFile = @(
    $Source + "SHDrive.vmdk"
    $Source + "SHDrive-flat.vmdk"
)
$Ignored = $IgnoreDir + $IgnoreFile

Робокопия:

Robocopy.exe /R:1 /W:0 $Source $Dest /E /V /TEE /XD $IgnoreDir /XF $IgnoreFile /LOG:$LogDir\RBCY_MD5_F.txt

MD5:

$SourceHash = Get-ChildItem "$Source\*.*" -Recurse -Force -Exclude $Ignored | Where-Object {!$_.psiscontainer } | Get-FileHash
$SourceHash | Select-Object "Hash", "path" | ft -HideTableHeaders -AutoSize | Out-File -Width "300" $LogDir\SRC_MD5_REF.txt
$SourceHash.Hash | Out-File $LogDir\SRC_MD5.txt 

Сравнение:

$Diff = Compare-Object -ReferenceObject $(get-content "$LogDir\SRC_MD5.txt") -DifferenceObject $(get-content "$LogDir\DST_MD5.txt")

Содержимое F:\ drive:

PS C:\Users\Robbi> Get-ChildItem F:\ -force


    Directory: F:\


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d--hs-       19/03/2019     06:40                $RECYCLE.BIN
d-----       16/05/2020     04:41                DATA
d-----       19/01/2020     06:34                Drivers
d-----       16/05/2020     04:55                Gumball
d-----       16/05/2020     04:58                SW
d--hs-       19/03/2019     06:36                System Volume Information
d-----       13/03/2020     16:08                Tools
d-----       12/12/2019     00:02                VMs
d-----       16/05/2020     04:55                _Pre-Cestino
-a----       08/02/2020     03:02    21474836480 SHDrive-flat.vmdk
-a----       08/02/2020     03:02            466 SHDrive.vmdk

Как я могу исключить данные, которые не хочу копировать, из списка get-children? В этом конкретном случае и, если возможно, "во всех случаях", когда Get-ChildItem должен исключить явный список содержимого (переменная строка и / или массив) во всей файловой системе.

1 ответ

Решение

Начиная с PowerShell 7.0, -Exclude а также -Include параметры поставщика командлетов, такие как Get-ChildItem работают только с именами элементов (имена файлов / каталогов в случае поставщика файловой системы), а не с полными путями.

Учитывая, что все пути, которые вы хотите исключить, являются прямыми потомками целевого каталога, я предлагаю двухэтапный подход:

# Get all files and directories in $Source, except those to be excluded.
# Note the use of \* instead of \*.*, so as to also include the
# directories (whose names don't have an extension).
$items = Get-Item $Source\* -Force | Where-Object FullName -NotIn $Ignored

# Recursively process all resulting files and directories and
# calculate their hashes.
# Note the use of -File to limit output to files.
$SourceHash = $items | Get-ChildItem -Recurse -Force -File | Get-FileHash

Конечно, если вы определите свой $Ignoredмассив в терминах файла / каталога имен только, вы могли бы использовать-Exclude:

# Convert the ignore list to file/directory names only.
$Ignored = $Ignored | Split-Path -Leaf

$SourceHash = Get-ChildItem -File $Source -Recurse -Force -Exclude $Ignored |
                Get-FileHash

Если пути для исключения могут встречаться на любом уровне иерархии подкаталогов, требуется дополнительная работа:

$ignoredRegex = '^(?:{0})(?:\{1}|$)' -f
                  ($Ignored.ForEach({ [regex]::Escape($_) }) -join '|'),
                  [IO.Path]::DirectorySeparatorChar


$SourceHash = Get-ChildItem $Source -Recurse -File -Force |
                Where-Object FullName -NotMatch $ignoredRegex
                  Get-FileHash

Вышеупомянутое использует регулярное выражение с -match, чтобы исключить все указанные пути и их дочерние элементы в любом месте дерева подкаталогов.

Другие вопросы по тегам