Измерьте несколько свойств?

Я хотел бы запросить каталог с помощью Get-ChildItem и создать таблицу со столбцами, такими как Path, Size(в ГБ), 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
    }

2 ответа

Решение

Возможно ли измерить несколько свойств с помощью одной команды?

Да, можно - только не так, как вам нужно .

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

Так что в лучшем случае мы можем сделать это, используя всего 2 витка трубопровода, чтобы :

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

PowerShell по умолчанию будет использовать табличный формат при отображении объектов с 4 или менее свойствами, поэтому вы можете ожидать, что вывод по умолчанию в оболочке будет примерно таким (в зависимости от языкового стандарта):

      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

Это возможно с помощью одного вызова команды с использованием вычисляемого свойства, которое преобразует свойство в числовой тип. Сейчас же -Sum с этим можно работать (правда, за эту сумму отбросим).

После того, как мы рассчитали статистику, мы конвертируем обратно в, чтобы получить значимые отображаемые значения.

Начиная с PS 7+, вычисляемое свойство можно использовать в качестве аргумента. Для более старых версий PS мы можем использовать для создания вычисляемого свойства.

Решение 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
    }
}

Объяснение:

  • Мы указываем два свойства в вызове:
    • 1-й объект недвижимости просто
    • 2-е свойство - это вычисляемое свойство , то есть оно получает свое значение при запуске небольшого блока скрипта. Блок скрипта преобразует в Int64 и использует его как значение, которое будет измеряться.
  • При указании нескольких свойств для он выводит массив, содержащий объект для каждого свойства, который содержит статистику.
    • $stats[0] содержит, а для Length собственность, из которой мы только берем.
    • $stats[1] содержит Sum, а для CreationTime собственность, из которой мы берем только Minimum и Maximum. Обратите внимание, что производит вывод типа [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 вызов.

Вывод

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

Другие вопросы по тегам