Когда у нас заканчивается место на диске, нам нужно знать, какие файлы нужно удалить, чтобы сэкономить место. В этой статье я поделюсь процессом создания функции для этого.

Чтобы просмотреть все файлы, мы используем Get-ChildItem с параметром -File. Для каждого объекта в возвращаемом списке мы можем получить доступ к его Length, чтобы получить размер файла в байтах.

> Get-ChildItem -Path .\.git\ -File |
>> ForEach-Object { Write-Host "$($_.Name): $($_.Length)" }
COMMIT_EDITMSG: 81
config: 384
description: 73
FETCH_HEAD: 95
HEAD: 21
index: 352958
index.windows: 353147
ORIG_HEAD: 41
packed-refs: 9279

Используя суффиксы множителя KB,MB,GB , мы можем преобразовать длину файла в удобочитаемые единицы.

> Get-ChildItem -Path .\.git\ -File |
>> ForEach-Object { Write-Host "$($_.Name): $($_.Length/1GB)" }
COMMIT_EDITMSG: 7.54371285438538E-08
config: 3.57627868652344E-07
description: 6.79865479469299E-08
FETCH_HEAD: 8.84756445884705E-08
HEAD: 1.9557774066925E-08
index: 0.00032871775329113
index.windows: 0.000328893773257732
ORIG_HEAD: 3.81842255592346E-08
packed-refs: 8.64174216985703E-06

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

Между тем, нам лучше округлить десятичные разряды в меньшую сторону.

> Get-ChildItem -Path .\.git\ -File |
ForEach-Object { Write-Host "$($_.Name):$([Math]::Round($_.Length/1KB, 2))KB, $([Math]::Round($_.Length/1MB, 2))MB, $([Math]::Round($_.Length/1GB, 2))GB" }
COMMIT_EDITMSG:0.08KB, 0MB, 0GB
config:0.38KB, 0MB, 0GB
description:0.07KB, 0MB, 0GB
FETCH_HEAD:0.09KB, 0MB, 0GB
HEAD:0.02KB, 0MB, 0GB
index:344.69KB, 0.34MB, 0GB
index.windows:344.87KB, 0.34MB, 0GB
ORIG_HEAD:0.04KB, 0MB, 0GB
packed-refs:9.06KB, 0.01MB, 0GB

Чтобы получить лучший формат вывода, мы можем использовать Select-Object вместо ForEach-Object. Команда Select-Object может использовать ScriptBlock для построения Property — добавлять настраиваемое свойство (вычисляемое-свойство) по запросу. В этом примере мы хотим показать свойство Length в единицах KB, MB, GB.

Давайте посмотрим, как это сделать.

> Get-ChildItem -Path .\.git\ -File |
>> Select-Object -Property Name, {[Math]::Round($_.Length/1KB, 2)}, {[Math]::Round($_.Length/1MB, 2)}, {[Math]::Round($_.Length/1GB, 2)}

Name           [Math]::Round($_.Length/1KB, 2) [Math]::Round($_.Length/1MB, 2) [Math]::Round($_.Length/1GB, 2)
----           ------------------------------- ------------------------------- -------------------------------
COMMIT_EDITMSG                            0,08                            0,00                            0,00
config                                    0,38                            0,00                            0,00
description                               0,07                            0,00                            0,00
FETCH_HEAD                                0,09                            0,00                            0,00
HEAD                                      0,02                            0,00                            0,00
index                                   344,69                            0,34                            0,00
index.windows                           344,87                            0,34                            0,00
ORIG_HEAD                                 0,04                            0,00                            0,00
packed-refs                               9,06                            0,01                            0,00

Блок сценария {} используется в качестве имени нового свойства. Чтобы сделать его более читабельным, нам нужно для него удобочитаемое имя свойства.

Для этого мы можем использовать хеш-таблицу: два ключа Labelи Expression

> Get-ChildItem -Path .\.git\ -File |
>> Select-Object -Property Name `
>> ,@{Label='Size(KB)'; Expression={[Math]::Round($_.Length/1KB, 2)}} `
>> ,@{Label='Size(MB)'; Expression={[Math]::Round($_.Length/1MB, 2)}} `
>> ,@{Label='Size(GB)'; Expression={[Math]::Round($_.Length/1GB, 2)}}

Name           Size(KB) Size(MB) Size(GB)
----           -------- -------- --------
COMMIT_EDITMSG     0,08     0,00     0,00
config             0,38     0,00     0,00
description        0,07     0,00     0,00
FETCH_HEAD         0,09     0,00     0,00
HEAD               0,02     0,00     0,00
index            344,69     0,34     0,00
index.windows    344,87     0,34     0,00
ORIG_HEAD          0,04     0,00     0,00
packed-refs        9,06     0,01     0,00

Теперь он выглядит намного лучше.

📓 Label может быть и Name . (Я не знаю, можно ли использовать другое строковое значение)

Следующей интересной вещью должна быть сортировка результата, чтобы показать самые большие файлы в верхней позиции — это то, что мы хотим сделать в начале.

Мы используем команду Sort-Object.

> Get-ChildItem -Path .\.git\ -File |
>> Select-Object -Property Name `
>> ,@{Label='Size(KB)'; Expression={[Math]::Round($_.Length/1KB, 2)}} `
>> ,@{Label='Size(MB)'; Expression={[Math]::Round($_.Length/1MB, 2)}} `
>> ,@{Label='Size(GB)'; Expression={[Math]::Round($_.Length/1GB, 2)}} |
>> Sort-Object { $_."Size(KB)" } -Descending

Name           Size(KB) Size(MB) Size(GB)
----           -------- -------- --------
index.windows    344,87     0,34     0,00
index            344,69     0,34     0,00
packed-refs        9,06     0,01     0,00
config             0,38     0,00     0,00
FETCH_HEAD         0,09     0,00     0,00
COMMIT_EDITMSG     0,08     0,00     0,00
description        0,07     0,00     0,00
ORIG_HEAD          0,04     0,00     0,00
HEAD               0,02     0,00     0,00

Когда мы рекурсивно проверяем весь том, например C:\, возвращаемых файлов будет слишком много для отображения, и тогда мы можем ограничить общее количество в списке.

Мы используем команду Select-Object с параметром -First.

> Get-ChildItem -Path 'C:\' -Recurse -File |
>> Select-Object -Property FullName `
>> ,@{Label='Size(KB)'; Expression={[Math]::Round($_.Length/1KB, 2)}} `
>> ,@{Label='Size(MB)'; Expression={[Math]::Round($_.Length/1MB, 2)}} `
>> ,@{Label='Size(GB)'; Expression={[Math]::Round($_.Length/1GB, 2)}}  |
>> Sort-Object { $_."Size(KB)" } -Descending |
>> Select-Object -First 5

Name                                                   Size(KB) Size(MB) Size(GB)
----                                                   -------- -------- --------
C:\...\IxNetwork-2018-11-15-09-38-33-P20816.dmp      2040997,07  1993,16     1,95
C:\...\IMG_1395.MOV                                  1296185,29  1265,81     1,24
C:\...\en_lzn7604002_r5a.alx                         1262491,46  1232,90     1,20
C:\...\Noto-unhinted.zip                             1088438,54  1062,93     1,04
C:\...\20220422_143651000_iOS.mp4                    831227,84    811,75     0,79

📓 Здесь мы используем FullName, чтобы показать абсолютные пути к файлам результатов, чтобы знать, где именно они находятся. Я просто скрываю путь под ..., который на самом деле не является реальным результатом команды.

Мы также можем использовать Where-Object для фильтрации тех файлов, размер которых больше заданного порогового значения, например 1GB.

> Get-ChildItem -Path 'C:\' -Recurse -File |
>> Select-Object -Property Name `
>> ,@{Label='Size(KB)'; Expression={[Math]::Round($_.Length/1KB, 2)}} `
>> ,@{Label='Size(MB)'; Expression={[Math]::Round($_.Length/1MB, 2)}} `
>> ,@{Label='Size(GB)'; Expression={[Math]::Round($_.Length/1GB, 2)}}  |
>> Sort-Object { $_."Size(KB)" } -Descending |
>> Where-Object { $_."Size(GB)" -ge 1 }

Name                                            Size(KB)    Size(MB)    Size(GB)
----                                            --------    --------    --------
C:\...\IxNetwork-2018-11-15-09-38-33-P20816.dmp 2040997,07  1993,16     1,95
C:\...\IMG_1395.MOV                             1296185,29  1265,81     1,24
C:\...\en_lzn7604002_r5a.alx                    1262491,46  1232,90     1,20
C:\...\Noto-unhinted.zip                        1088438,54  1062,93     1,04

📓 Мы используем -ge 1 вместо -ge 1GB выше в столбце «Размер (ГБ)», поскольку мы уже преобразовали Length из байтов в GB .

Однако, чтобы сделать его более гибким, мы можем использовать исходное значение Length для фильтрации — мы можем использовать любое значение с суффиксами множителя для фильтрации.

> Get-ChildItem -Path '.\.git\' -Recurse -File |
>> Select-Object -Property Name, Length `
>> ,@{Label='Size(KB)'; Expression={[Math]::Round($_.Length/1KB, 2)}} `
>> ,@{Label='Size(MB)'; Expression={[Math]::Round($_.Length/1MB, 2)}} `
>> ,@{Label='Size(GB)'; Expression={[Math]::Round($_.Length/1GB, 2)}}  |
>> Where-Object { $_.Length -ge 10MB } |
>> Sort-Object { $_."Size(KB)" } -Descending | Select-Object -First 10 |
>> Format-Table

Name                                                  Length  Size(KB) Size(MB) Size(GB)
----                                                  ------  -------- -------- --------
dbb48e5c36dcdc708b5935a885bb30687431a7             115862011 113146,50   110,49     0,11
pack-d6844473eef0db2aa2ac0a8c3933f3c6716fa798.pack  33116617  32340,45    31,58     0,03
> Get-ChildItem -Path '.\.git\' -Recurse -File |
>> Select-Object -Property Name, Length `
>> ,@{Label='Size(KB)'; Expression={[Math]::Round($_.Length/1KB, 2)}} `
>> ,@{Label='Size(MB)'; Expression={[Math]::Round($_.Length/1MB, 2)}} `
>> ,@{Label='Size(GB)'; Expression={[Math]::Round($_.Length/1GB, 2)}}  |
>> Where-Object { $_.Length -ge 200KB } |
>> Sort-Object { $_."Size(KB)" } -Descending | Select-Object -First 10 | Format-Table

Name                                                  Length  Size(KB) Size(MB) Size(GB)
----                                                  ------  -------- -------- --------
dbb48e5c36dcdc708b5935a885bb30687431a7             115862011 113146,50   110,49     0,11
pack-d6844473eef0db2aa2ac0a8c3933f3c6716fa798.pack  33116617  32340,45    31,58     0,03
pack-d6844473eef0db2aa2ac0a8c3933f3c6716fa798.idx    1603624   1566,04     1,53     0,00
2703fe3cbc651d7541e17f3885b5eec2d4c643                394368    385,12     0,38     0,00
index.windows                                         353147    344,87     0,34     0,00
index                                                 352958    344,69     0,34     0,00

📓 Чтобы использовать Length в качестве столбца фильтрации, нам нужно добавить Length в список -Property .

Кроме того, мы можем использовать Out-GridView для отображения списка результатов в интерактивном окне.

> Get-ChildItem -Path '.\.git\' -Recurse -File |
>> Select-Object -Property Name, Length `
>> ,@{Label='Size(KB)'; Expression={[Math]::Round($_.Length/1KB, 2)}} `
>> ,@{Label='Size(MB)'; Expression={[Math]::Round($_.Length/1MB, 2)}} `
>> ,@{Label='Size(GB)'; Expression={[Math]::Round($_.Length/1GB, 2)}}  |
>> Where-Object { $_.Length -ge 200KB } |
>> Sort-Object { $_."Size(KB)" } -Descending | Select-Object -First 10 |
>> Out-GridView

В интерактивном окне Out-GridView мы можем динамически сортировать и фильтровать список результатов. Это очень полезно для длинного списка результатов.

Наконец, мы можем поместить все коды в функцию для повторного использования.

<# 
.SYNOPSIS
    Find big files in the given path.

.DESCRIPTION
    Find files in the given path, sort by size and return top ones.

.PARAMETER Path
 The target path where to find big files.

.PARAMETER Threshould
 The size threshould for found result files.

.PARAMETER First
 How many top big files to show and return.
 
.PARAMETER ShowByGridView
 $true to show result in gridview, $false to show in console by table.

.EXAMPLE
    Find-BigFiles -Path "C:\Users\wenijinew" -First 20
 
.EXAMPLE
    Find-BigFiles -Path "C:\Users\wenijinew" -Threshould 100MB
 
.EXAMPLE
    Find-BigFiles -Path "C:\Users\wenijinew" -Threshould 1GB -ShowByGridView $true
#>
Function Find-BigFiles($Path, $Threshould=$null, $First=10, $ShowByGridView=$false){
 $Files = Get-ChildItem -Path $Path -Recurse -Force -File |
   Select-Object -Property FullName, Length `
    ,@{Name='Size(GB)';Expression={[Math]::Round($_.Length / 1GB, 2)}} `
    ,@{Name='Size(MB)';Expression={[Math]::Round($_.Length / 1MB, 2)}} `
    ,@{Name='Size(KB)';Expression={[Math]::Round($_.Length / 1KB, 2)}}

 if ($Threshould -ne $null){
  $Files = $Files | Where-Object { $_.Length -ge $Threshould }
 }

 $Files = $Files | Sort-Object { $_.Length } -Descending | Select-Object -First $First 

 if ($ShowByGridView -eq $true){
  $Files | Out-GridView
 }else{
  $Files | Format-Table
 }
 
 return $Files
}

Заворачивать

В этой статье мы реализуем одну функцию для пошагового поиска больших файлов. Он охватывает следующие функции и знакомит с использованием нескольких комлетов.

  • Получите доступ к размеру файлов на Length объектов, возвращенных Get-ChildItem
  • Преобразование Length единиц из байтов в KB, MB, GB
  • Создайте настроенное свойство путем вычисления исходного свойства — Length файлового объекта.
  • Фильтровать объекты по Where-Object
  • Сортировать объекты по Sort-Object
  • Вернуть первые n объектов по -First из Select-Object
  • Используйте Format-Table для форматирования свойств объектов
  • Используйте Out-GridView для отображения вывода в интерактивном окне, где поддерживаются динамическая сортировка и фильтрация.

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

Рекомендации