以前、PowerShell でフォルダサイズの一覧を取得する話をしました。
あれから一年。事ある毎に PowerShell でスクリプトを書き書きしてきた私は、ふと思い立ってこのスクリプトに再挑戦することにしました。別に、前に作ったファイルを失くしたとかじゃないですよ。
さて、前より上手に書けるかな?
コード
one-liner
Get-ChildItem -Recurse -Directory | ForEach-Object {$childItems = @(Get-ChildItem -LiteralPath $_.FullName -File); [long]$totalLength = ($childItems | Measure-Object Length -Sum).Sum; [PSCustomObject]@{Length = $totalLength; LengthMB = [Math]::Round($totalLength / 1MB, 2); LengthGB = [Math]::Round($totalLength / 1GB, 2); Count = $childItems.Length; FullName = $_.FullName}}
function
Gist でご覧ください。開いたページでスクリプトをダウンロードできます。
get_the_list_of_directory_size.psm1 · GitHub
モジュールファイル (.psm1) の使い方はお調べください。Set-ExecutionPolicy
と Import-Module
ができれば OK です。
使い方
one-liner
目的のフォルダまで移動して、 one-liner のコードを貼り付ける
function
目的のフォルダまで移動して、
Get-ChildItem -Recurse -Directory | Measure-Directory
ただこれだとフォルダサイズをコンソール画面に吐き出し続けるだけですので、容量を食っているフォルダの特定はできません。ですので結果を変数に格納してソートしましょう。
結果を変数に格納してソート
one-liner
目的のフォルダまで移動して、
# 変数に格納 $directorySize = Get-ChildItem -Recurse -Directory | ForEach-Object {$childItems = @(Get-ChildItem -LiteralPath $_.FullName -File); [long]$totalLength = ($childItems | Measure-Object Length -Sum).Sum; [PSCustomObject]@{Length = $totalLength; LengthMB = [Math]::Round($totalLength / 1MB, 2); LengthGB = [Math]::Round($totalLength / 1GB, 2); Count = $childItems.Length; FullName = $_.FullName}} # ソート $directorySize | Where-Object {$_.Length -gt 0} | Sort-Object -Property Length -Descending | Format-Table
function
目的のフォルダまで移動して、
$directorySize = Get-ChildItem -Recurse -Directory | Measure-Directory $directorySize | Where-Object {$_.Length -gt 0} | Sort-Object -Property Length -Descending | Format-Table
お目当ての、容量を食っているフォルダが見つかるまで、カレントディレクトリを移動しながらフォルダサイズを取得し続けてください。
「戻り値を変数に入れてソート……
戻り値を変数に入れてソート……」
「容量を、食ってる…」
実行結果
Length LengthMB LengthGB Count FullName ------ -------- -------- ----- -------- 581483418 554.55 0.54 16 D:\Users\taidalog\Documents\SCAN\MY_BA01 152654799 145.58 0.14 24 D:\Users\taidalog\Documents\copy_test_destination\6\Measure-ExcelFunction 152654799 145.58 0.14 24 D:\Users\taidalog\Documents\copy_test_destination\1\Measure-ExcelFunction 152654799 145.58 0.14 24 D:\Users\taidalog\Documents\copy_test_source\Measure-ExcelFunction 132750224 126.6 0.12 4 D:\Users\taidalog\Documents\SCAN\2018_04_11 102631614 97.88 0.1 2 D:\Users\taidalog\Documents\SCAN\CR_S01 98804736 94.23 0.09 1 D:\Users\taidalog\Documents\mail 64119151 61.15 0.06 3 D:\Users\taidalog\Documents\SCAN\2018_05_03 57829436 55.15 0.05 11 D:\Users\taidalog\Documents\SCAN\2017_10_02 20596518 19.64 0.02 7 D:\Users\taidalog\Documents\copy_test_destination\6\class_news_move
ちょっとした説明
function の process
ブロックの中、
$childItems = @(Get-ChildItem -LiteralPath $convertedPath -File) (中略) Count = $childItems.Length
で各フォルダ内のファイル数を取得しています。これは @()
を外して
$childItems = Get-ChildItem -Path $convertedPath -File (中略) Count = $childItems.Length
としても動くには動きます。
ではなぜ @()
でくくっているかというと、Get-ChildItem
の戻り値を確実に配列として扱いたいからです。
Get-ChildItem
した結果、フォルダ内にファイルが複数個あった場合は、戻り値は配列 Object[]
になります。配列の Length
プロパティを取得すると、要素数が得られます。これがフォルダ内のファイル数ですね。
一方でファイルが1つしかなかった場合、戻り値は要素数1の配列……ではなく、FileInfo
なり DirectoryInfo
なりの単体のオブジェクトです。そしてファイルの Length
プロパティを取得すると、得られるのはファイルサイズです。ファイルの個数を調べたいのに、ファイルサイズを取得してしまうのです。
ここで @()
の出番です。単体のオブジェクトを @()
でくくると、要素数1の配列になります。これで Length
プロパティが要素数を返すようになります。
一年前と比べて
独学で遊んでいるだけにしては結構進歩していると思います。
- コピペせず自分で書けた
PSCustomObject
を使えるようになった- Pipeline の流れを理解できるようになった
うん、進歩しているな。
続編
こちらもぜひ。
変更履歴
- 「コード」の「one-liner」の
$totalLength
の型を[int]
から[long]
に変更 (2021/06/08) - 「コード」の「one-liner」の
Get-ChildItem
のパスを指定するパラメータを-Path
から-LiteralPath
に変更 (2021/06/08) - 「コード」の「function」の function を Gist で公開するように変更 (2021/06/09)
- :3.0 へのリンクを追加 (2021/06/10)
- :3.0+1.0 へのリンクを追加 (2021/06/22)
- 目次の下に「こちらもどうぞ」を追加 (2021/09/09)
- 「更新履歴」を追加 (2021/09/09)