Подтвердить что ты не робот

Объедините результаты двух разных вызовов Get-ChildItem в одну переменную, чтобы сделать одну и ту же обработку на них

Я пытаюсь написать PowerShell script для создания списка файлов из нескольких каталогов. После того, как все каталоги были добавлены в основной список, я хотел бы сделать такую ​​же обработку для всех файлов.

Это то, что у меня есть:

$items = New-Object Collections.Generic.List[IO.FileInfo]

$loc1 = @(Get-ChildItem -Path "\\server\C$\Program Files (x86)\Data1\" -Recurse)
$loc2 = @(Get-ChildItem -Path "\\server\C$\Web\DataStorage\" -Recurse)

$items.Add($loc1) # This line fails (the next also fails)
$items.Add($loc2)

# Processing code is here

который не работает с этой ошибкой:

Невозможно преобразовать аргумент "0", с value: "System.Object []", для "Добавить" в type "System.IO.FileInfo": "Не удается конвертировать "System.Object []" va lue типа "System.Object []" для ввода типа "System.IO.FileInfo" ".

Меня больше интересует, какой правильный подход для этого типа ситуации. Я понимаю, что мой код очень похож на C - если есть больше возможностей PowerShell для выполнения одной и той же задачи, я Все для этого. Ключ состоит в том, что число $loc#'s может меняться со временем, поэтому добавление и удаление одного или двух должно быть легко в полученном коде.

4b9b3361

Ответ 1

Не уверен, что вам нужен общий список. Вы можете просто использовать массив PowerShell, например:

$items  = @(Get-ChildItem '\\server\C$\Program Files (x86)\Data1\' -r)
$items += @(Get-ChildItem '\\server\C$\Web\DataStorage\' -r)

Массивы PowerShell могут быть объединены с помощью +=.

Ответ 2

Из get-help get-childitem:  -Дорожка     Указывает путь к одному или нескольким местоположениям. Разрешены маски. Расположение по умолчанию - это текущий каталог (.).

$items = get-childitem '\\server\C$\Program Files (x86)\Data1\','\\server\C$\Web\DataStorage\' -Recurse

Ответ 3

Ответ Keith - это способ PowerShell: просто используйте @(...) + @(...).

Если вам действительно нужен список типов [IO.FileInfo], вам необходимо использовать AddRange и передать массив объектов в массив FileInfo - вам также необходимо убедиться, что вы не получаете никаких объектов DirectoryInfo, или вам нужно использовать IO.FileSystemInfo в качестве типа списка:

Итак, избегайте каталогов:

$items = New-Object Collections.Generic.List[IO.FileInfo]
$items.AddRange( ([IO.FileSystemInfo[]](ls '\\server\C$\Program Files (x86)\Data1\' -r | Where { -not $_.PSIsContainer } )) )
$items.AddRange( ([IO.FileSystemInfo[]](ls '\\server\C$\Web\DataStorage\' -r | Where { -not $_.PSIsContainer } )) )

Или используйте FileSystemInfo (общий базовый класс FileInfo и DirectoryInfo):

$items = New-Object Collections.Generic.List[IO.FileSystemInfo]
$items.AddRange( ([IO.FileSystemInfo[]](ls '\\server\C$\Program Files (x86)\Data1\' -r)) )
$items.AddRange( ([IO.FileSystemInfo[]](ls '\\server\C$\Web\DataStorage\' -r)) )

Ответ 4

Вот, возможно, еще больше способ PowerShell-ish, который не требует конкатенации частей или явного добавления элементов в результат:

# Collect the results by two or more calls of Get-ChildItem
# and perhaps do some other job (but avoid unwanted output!)
$result = .{

    # Output items
    Get-ChildItem C:\TEMP\_100715_103408 -Recurse

    # Some other job
    $x = 1 + 1

    # Output some more items
    Get-ChildItem C:\TEMP\_100715_110341 -Recurse

    #...
}

# Process the result items
$result

Но код внутри блока script должен быть написан немного более тщательно, чтобы избежать нежелательного вывода, смешанного вместе с элементами файловой системы.

EDIT: альтернативно и, возможно, более эффективно, вместо .{ ... } мы можем используйте @( ... ) или $( ... ), где ... обозначает код, содержащий несколько вызовы Get-ChildItem.

Ответ 5

-Filter более эффективен, чем -Include, поэтому, если у вас нет большого количества разных расширений, просто конкатенация двух фильтрованных списков может быть быстрее.

$files  = Get-ChildItem -Path "H:\stash\" -Filter *.rdlc -Recurse 
$files += Get-ChildItem -Path "H:\stash\" -Filter *.rdl  -Recurse 

Я сравнил вывод с таймером следующим образом:

$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
# Do Stuff Here
$stopwatch.Stop()
Write-Host "$([Math]::Round($stopwatch.Elapsed.TotalSeconds)) seconds ellapsed"