タイダログ

もっと怠けますか? (y/n)

PowerShell でフォルダサイズの一覧を取得する:2.0 ADVANCE.

以前、PowerShell でフォルダサイズの一覧を取得する話をしました。

taidalog.hatenablog.com

あれから一年。事ある毎に 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-ExecutionPolicyImport-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 の流れを理解できるようになった

うん、進歩しているな。

続編

こちらもぜひ。

taidalog.hatenablog.com

taidalog.hatenablog.com

変更履歴

  • 「コード」の「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)