Get-ChildItem.Length是错误的

Lot*_*i11 2 arrays powershell member-enumeration

我正在编写一个遍历目录的递归函数,并复制其中的每个文件和文件夹.我在函数中的第一个检查是查看传入的路径是否有子节点.为了找到这个,我使用以下方法:

[array]$arrExclude = @("Extras")
Function USBCopy
{
Param ([string]$strPath, [string]$strDestinationPath)
    try
    {
        $pathChildren = Get-ChildItem -Path $strPath
        if($pathChildren.Length -gt 0)
        {
            foreach($child in $pathChildren)
            {
                if($arrExclude -notcontains $child)
                {
                    $strPathChild = "$strPath\$child"
                    $strDestinationPathChild = "$strDestinationPath\$child" 
                    Copy-Item $strPathChild -Destination $strDestinationPathChild
                    USBCopy $strPathChild $strDestinationPathChild  
                }   
            }
        }              
    }
    catch
    {
        Write-Error ("Error running USBCopy: " + $Error[0].Exception.Message)
    }    
}
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,我的函数可以工作,但我的代码会说当一个目录实际上有一个文件时它是空的.当我调试我的函数时,变量会说该文件夹有子项但变量的长度为0.任何人都知道如何解决这个问题?

mkl*_*nt0 6

PetSerAl,在很多次之前,已经在问题的简短评论中提供了关键指针(并且他也帮助改进了这个答案):

$pathChildren = @(Get-ChildItem -Path $strPath)
Run Code Online (Sandbox Code Playgroud)

使用@(...)中,阵列子表达式运算符,可以确保,无论封闭命令输出被视为一个阵列,即使只有1目的是输出,以便.Length被保证是阵列.Length属性.

但是,在PSv3 +中,访问.Count而不是.LengthWillPanic的有用答案一样,也可以使用 - 见下文.

如果没有@(...),结果可能是单个对象,因为PowerShell会自动解包仅包含1个对象的输出集合,该集合仅生成一个对象,这意味着以下内容:

  • PSv2:

    • 如果该对象恰好具有.Length属性,则返回值.
      在这种情况下,如果返回的唯一对象表示一个文件(一个[System.IO.FileInfo]实例)(如果该目录只包含1个文件且没有子目录,则隐藏的项目除外),则这是真的.
      一个[System.IO.FileInfo]实例的.Length属性以字节为单位返回文件的大小.值为0暗示空文件.
      (如果返回的唯一对象是一个目录(一个[System.IO.DirectoryInfo]实例,.Length将返回$null,因为这样的实例没有.Length属性.)
  • 在PSv3 +,解决方法是不再严格需要的,如果使用.Count,因为可以治疗甚至一个标量(单个对象),就好像它一个阵列,其中隐式 .Length/.Count[1] 的属性和能力指数为(例如,
    <scalar>[0])
    ,但有一些警告:

    • 如果有效Set-StrictMode -Version 2或更高有效,则访问.Length.Count实际上不存在于标量上的属性会导致错误.
      然而,这种行为非常不幸,因为这些属性应该被认为是隐含存在的- 如果您同意,请在此GitHub问题中听取您的意见.

    • 如果标本身具有这样的属性作为.Length.Count或支持索引,即优先 -这就是为什么.Count要在这种情况下使用(如说明,[System.IO.FileInfo]实例有.Length物业报告以字节为单位的文件大小); 见下面的例子.

    • 使用@(...)避免这种冲突,因为结果总是一个数组.

    • 成员枚举是统一的补充方面,它允许您在集合级别应用集合包含的项的成员(属性或方法),在这种情况下,成员可以隐式访问集合中的每个项目,并且结果值以数组形式返回; 见下面的例子. 要解决与成员枚举的名称冲突,需要采用不同的方法 - 请参阅我的这个答案.


PSv3 +统一集合处理的示例

PS> (666).Length
1  # Scalar 666 was implicitly treated as a collection of length 1

PS> (666).Count
1  # Ditto - ** .Count is preferable, because it less often means something else **

# Caveat: A *string* scalar has a native .Length property
PS> ('666').Length; ('666').Count
3  # .Length: The string types's native property: the number of *characters*
1  # .Count: PowerShell's implicit collection handling: 1 *element*

PS> (666)[0]; (666)[-1]
666  # Index [0] always yields the scalar itself.
666  # Ditto for [-1], the *last* element.

# Member enumeration example: get the .Day property value from each
# [datetime] instance stored in an array.
PS> ((Get-Date), (Get-Date).AddDays(-1)).Day
20
19
Run Code Online (Sandbox Code Playgroud)

[1]正如PetSerAl指出的那样,直到PSv5.1,数组的.Count属性是一个别名属性.Length,由PowerShell的ETS(扩展类型系统 - 参见Get-Help about_Types.ps1xml.但是,这个别名属性自PSv3以来并没有真正需要已实现的.NET接口类型成员也被PowerShell公开,提供对数组类型ICollection.Count属性的访问.因此v6将不再具有别名属性,此时.Count将直接访问ICollection.Count- 请参阅此GitHub问题.
请注意,PowerShell魔术仍然涉及到然而,它涉及调用.Count"假"数组(标量).