1

我想使用 Get-ChildItem 查询一个目录,并创建一个包含路径、大小(以 Gb 为单位)、MinimumCreationTime、MaximumCreationTime 等列的表。在 foreach 循环中,我编写了 3 个测量命令。是否可以使用一个命令测量多个属性?

$pathes = @'
C:\open
C:\games
'@.Split([System.Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries)

foreach ($path in $pathes){
    Get-ChildItem $path -Recurse | Measure Length -Sum 
    Get-ChildItem $path -Recurse | Measure CreationTime -Minimum
    Get-ChildItem $path -Recurse | Measure CreationTime -Maximum
    }
4

2 回答 2

3

是否可以使用一个命令测量多个属性?

是的,你可以——只是不是你需要的方式

我们在这里不能完全整合所有三个调用的原因是它将对每个输入属性Measure-Object执行所有请求的计算——并且它不能有意义地计算多个值的总和。[datetime]

所以充其量,我们只需要 2 轮管道就可以做到Measure-Object

$paths = 'C:\open','C:\games'

foreach ($path in $paths){
    # Let's call Get-ChildItem ONCE, and store the result
    $children = Get-ChildItem $path -Recurse 

    # Now let's do our calculations
    $fileSize = $children | Measure Length -Sum 
    $newAndOld = $children | Measure CreationTime -Minimum -Maximum

    # And finally create a new object to hold the details we calculated above
    [pscustomobject]@{
      Path           = $path
      TotalSize      = $fileSize.Sum
      OldestFileTime = $newAndOld.Minimum
      NewestFileTime = $newAndOld.Maximum
    }
}

当显示具有 4 个或更少属性的对象时,PowerShell 将默认为表格格式,因此您可以期望 shell 中的默认输出是这样的(取决于语言环境):

Path      TotalSize OldestFileTime       NewestFileTime
----      --------- --------------       --------------
C:\open  1234567890 1/1/2018 2:00:00 AM  1/31/2021 7:45:00 PM
C:\games 1234567890 1/1/2018 2:00:00 AM  1/31/2021 7:45:00 PM
于 2021-03-18T19:13:07.213 回答
2

使用将属性转换为数字类型Measure-Object的计算属性,可以通过对命令的一次调用来实现。CreationTime现在-Sum可以使用它(尽管我们将丢弃 的总和CreationTime)。

在我们计算完统计数据后,我们转换回[DateTime]以获取有意义的显示值。

从 PS 7+ 开始,计算的属性可以用作Measure-Object参数。对于较旧的 PS 版本,我们可以使用它Select-Object来创建计算属性。

PS 7+ 解决方案

foreach ($path in $pathes){

    $stats = Get-ChildItem $path -File -Recurse | 
             Measure-Object 'Length', { $_.CreationTime.Ticks } -Sum -Minimum -Maximum

    # Create the output for one table row
    [PSCustomObject]@{
        Path                = $path
        'Size(GB)'          = [math]::Round( $stats[0].Sum / 1GB, 2 )   # 2 = number of digits
        MinimumCreationTime = [DateTime] [Int64] $stats[1].Minimum
        MaximumCreationTime = [DateTime] [Int64] $stats[1].Maximum
    }
}

解释:

  • 我们在调用中指定了两个属性Measure-Object
    • 第一个属性只是Length
    • 第二个属性是一个计算属性,这意味着它通过运行一个小脚本块来获取它的值。脚本块将其转换CreationTimeInt64并将其用作将要测量的值。
  • 当为 指定多个属性时Measure-Object,它会输出一个数组,其中包含每个属性的对象,其中包含统计信息。
    • $stats[0]包含Sum,MinimumMaximumLength属性,我们只取Sum.
    • $stats[1]包含Sum,MinimumMaximumCreationTime属性,我们只取MinimumMaximum。请注意,Measure-Object产生类型的输出[double],所以我们首先必须转换回[Int64]之前最终转换回[DateTime]

PS 5 解决方案

foreach ($path in $pathes){

    $stats = Get-ChildItem $path -File -Force | 
        Select-Object Length, @{ name = 'CreationTimeTicks'; expression = { $_.CreationTime.Ticks } } | 
        Measure-Object Length, CreationTimeTicks -Sum -Minimum -Maximum

    # Create the output for one table row - identical to PS 7+ solution
    [PSCustomObject]@{
        Path                = $path
        'Size(GB)'          = [math]::Round( $stats[0].Sum / 1GB, 2 )   # 2 = number of digits
        MinimumCreationTime = [DateTime] [Int64] $stats[1].Minimum
        MaximumCreationTime = [DateTime] [Int64] $stats[1].Maximum
    }
}

解释:

这类似于 PS 7+ 的解决方案,不同之处在于我们用于Select-Object创建一个名为 的计算属性CreationTimeTicks,因此我们可以将其按名称传递给Measure-Object调用。

结论

虽然此代码似乎有效,但此答案提供的代码在概念上更清晰,因此我会使用它。

于 2021-03-18T19:59:21.213 回答