将两个不同的 Get-ChildItem 调用的结果合并到单个变量中以对它们进行相同的处理

发布于 2024-10-13 05:06:00 字数 859 浏览 5 评论 0原文

我正在尝试编写一个 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[]”,用于“添加”到 输入“System.IO.FileInfo”:“不能 转换“System.Object[]”值 类型为“System.Object[]”的类型 “系统.IO.文件信息”。”

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

I'm trying to write a PowerShell script to build a list of files, from several directories. After all directories have been added to the main list, I'd like to do the same processing on all files.

This is what I have:

$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

which fails with this error:

Cannot convert argument "0", with
value: "System.Object[]", for "Add" to
type "System.IO.FileInfo": "Cannot
convert the "System.Object[]" va lue
of type "System.Object[]" to type
"System.IO.FileInfo"."

I am mostly interested in what is the correct approach for this type of situation. I realize that my code is a very C way of doing it -- if there is a more PowerShell way to acomplish the same task, I'm all for it. The key, is that the number of $loc#'s may change over time, so adding and removing one or two should be easy in the resulting code.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

漫雪独思 2024-10-20 05:06:00

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

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

可以使用 += 连接 PowerShell 数组。

Not sure you need a generic list here. You can just use a PowerShell array e.g.:

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

PowerShell arrays can be concatenated using +=.

夏夜暖风 2024-10-20 05:06:00

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

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

From get-help get-childitem:
-Path
Specifies a path to one or more locations. Wildcards are permitted. The default location is the current directory (.).

$items = get-childitem '\\server\C$\Program Files (x86)\Data1\','\\server\C$\Web\DataStorage\' -Recurse
梦归所梦 2024-10-20 05:06:00

这里有一些可能更类似于 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

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

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

Here is some perhaps even more PowerShell-ish way that does not need part concatenation or explicit adding items to the result at all:

# 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

But the code inside the script block should be written slightly more carefully to avoid unwanted output mixed together with file system items.

EDIT: Alternatively, and perhaps more effectively, instead of .{ ... } we can
use @( ... ) or $( ... ) where ... stands for the code containing several
calls of Get-ChildItem.

苏辞 2024-10-20 05:06:00

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)) )

Keith's answer is the PowerShell way: just use @(...)+@(...).

If you actually do want a typesafe List[IO.FileInfo], then you need to use AddRange, and cast the object array to a FileInfo array -- you also need to make sure you don't get any DirectoryInfo objects, or else you need to use IO.FileSystemInfo as your list type:

So, avoid directories:

$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 } )) )

Or use FileSystemInfo (the common base class of FileInfo and 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)) )
入怼 2024-10-20 05:06:00

-Filter-Ininclude 性能更高,因此,如果您没有很多不同的扩展名,那么简单地连接两个过滤列表可能会更快。

$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"

-Filter is more performant than -Include, so if you don't have a lot of different extensions, simply concatenating two filtered lists might be faster.

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

I compared the output with a timer like this:

$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
# Do Stuff Here
$stopwatch.Stop()
Write-Host "$([Math]::Round($stopwatch.Elapsed.TotalSeconds)) seconds ellapsed"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文