21

我正在尝试编写一个 PowerShell 脚本来构建来自多个目录的文件列表。将所有目录添加到主列表后,我想对所有文件进行相同的处理。

这就是我所拥有的:

$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”,值为:“System.Object[]”,用于“Add”以键入“System.IO.FileInfo”:“无法转换“System.Object[]”类型的“System.Object[]”值。 Object[]”来输入“System.IO.FileInfo”。

我最感兴趣的是这种情况的正确方法是什么。我意识到我的代码是一种非常C的方式——如果有更多的 PowerShell 方式来完成相同的任务,我完全赞成。关键是数量$loc#'s可能会随着时间而变化,因此在生成的代码中添加和删除一两个应该很容易。

4

5 回答 5

34

不确定您是否需要一个通用列表。您可以只使用 PowerShell 数组,例如:

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

PowerShell 数组可以使用+=.

于 2011-01-20T16:56:41.593 回答
29

From get-help get-childitem: -Path 指定一个或多个位置的路径。允许使用通配符。默认位置是当前目录 (.)。

$items = get-childitem '\\server\C$\Program Files (x86)\Data1\','\\server\C$\Web\DataStorage\' -Recurse
于 2011-01-20T19:16:18.503 回答
6

这里有一些可能更类似于 PowerShell 的方式,它根本不需要部分连接或显式添加项目到结果中:

# 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

但是脚本块内的代码应该稍微更仔细地编写以避免不需要的输出与文件系统项混合在一起。

编辑:或者,也许更有效的是,.{ ... }我们可以使用@( ... )or $( ... )where...代表包含多个调用的代码,而不是Get-ChildItem.

于 2011-01-20T18:11:45.530 回答
5

Keith 的回答是 PowerShell 方式:只需使用 @(...)+@(...)。

如果你确实想要一个类型安全的 List[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)) )
于 2011-01-20T17:41:32.560 回答
0

-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"
于 2016-11-28T16:43:11.453 回答