PowerShell Get Folders And Files Size

2022-03-03

說明如何使用 PowerShell 計算資料夾與檔案的大小。

logo

說明

路徑下所有檔案的大小

get-childitem | select name, @{Name='FileSize'; Exp = {"{0:N0}" -f ($_.Length / 1KB)}}

資料夾檔案總和

(get-childitem c:\users\sdwh\ | measure Length -s).sum / 1MB

路徑下檔案與資料夾的檔案數以及檔案大小總和

結果會自動輸出至目前目錄下的 folder_sizes.csv

$directory = Get-Location
$global:report = @()

function Process-Folder {
    param (
        [string]$folderPath
    )

    $folderInfo = [PSCustomObject]@{
        FullPath = $folderPath
        FileCounts = (Get-ChildItem -Path $folderPath -File).Count
        FolderCounts = (Get-ChildItem -Path $folderPath -Directory).Count
        'TotalSize(MB)' = [math]::Round((Get-ChildItem -Path $folderPath -File | Measure-Object -Property Length -Sum).Sum / 1MB, 2)
    }

    $global:report += $folderInfo
    $subfolders = Get-ChildItem -Path $folderPath -Directory
    foreach ($subfolder in $subfolders) {
        Process-Folder -folderPath $subfolder.FullName
    }
}

Process-Folder -folderPath $directory

$global:report | Export-Csv -Path "folder_sizes.csv" -NoTypeInformation

⭐資料夾比較 (左、右側專有;共用但雜湊不同)

function Get-DirectoryContentsInfo {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$currentDirectory
    )

    $hash = @{}
    
    Get-ChildItem -Path $currentDirectory -Recurse | ForEach-Object {
        $relativePath = $_.FullName.Replace($currentDirectory, '')
        $hash[$relativePath] = @{
            Size = ($_.Length / 1KB)
            Hash = (Get-FileHash -Algorithm SHA1 -Path $_.FullName).Hash
        }
    }
    
    return $hash
}

function Compare-HashTables {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [HashTable]$hash1,

        [Parameter(Mandatory = $true)]
        [HashTable]$hash2
    )

    $set1 = New-Object 'System.Collections.Generic.HashSet[string]'
    $set2 = New-Object 'System.Collections.Generic.HashSet[string]'
    $keys1 = $hash1.Keys
    $keys2 = $hash2.Keys

    foreach ($key in $keys1) { $set1.Add($key) }
    foreach ($key in $keys2) { $set2.Add($key) }

    $set1Copy = New-Object 'System.Collections.Generic.HashSet[string]' $set1
    $set2Copy = New-Object 'System.Collections.Generic.HashSet[string]' $set2

    $set1.IntersectWith($set2)
    $set1Copy.ExceptWith($set2)
    $set2Copy.ExceptWith($set1)

    return [PSCustomObject]@{
        LeftOnly  = $set1Copy
        RightOnly = $set2Copy
        Both      = $set1
    }
}

function Compare-FilesAndExport {
    param (
        [Hashtable]$left,
        [Hashtable]$right,
        [String]$path
    )

    $results = @()
    
    $left.Keys | ForEach-Object {
        $item = $_
        
        if (!$right.ContainsKey($item)) {
            $results += [PSCustomObject]@{
                Status   = "Left"
                FullPath = $item
                Size     = $left[$item].Size
                Hash     = $left[$item].Hash
                Size2    = $null
                Hash2    = $null
            }
        } else {
            if ($left[$item].Hash -eq $right[$item].Hash) {
                $results += [PSCustomObject]@{
                    Status   = "Same"
                    FullPath = $item
                    Size     = $left[$item].Size
                    Hash     = $left[$item].Hash
                    Size2    = $null
                    Hash2    = $null
                }
            } else {
                $results += [PSCustomObject]@{
                    Status   = "Different"
                    FullPath = $item
                    Size     = $left[$item].Size
                    Hash     = $left[$item].Hash
                    Size2    = $right[$item].Size
                    Hash2    = $right[$item].Hash
                }
            }
        }
    }

    $right.Keys | ForEach-Object {
        $item = $_
        
        if (!$left.ContainsKey($item)) {
            $results += [PSCustomObject]@{
                Status   = "Right"
                FullPath = $item
                Size     = $right[$item].Size
                Hash     = $right[$item].Hash
                Size2    = $null
                Hash2    = $null
            }
        }
    }

    $results | Sort-Object -Property Status | Export-Csv -Path $path -NoTypeInformation
}


$left = get-DirectoryContentsInfo 'D:\dir1'
$right = get-DirectoryContentsInfo 'D:\dir2'
$res = compare-HashTables $left $right

Compare-FilesAndExport $left $right "output.csv"

相關連結

PowerShell 使用者不能錯過的 5 個技巧

Powershell 使用物件與資料結構 (Array, Hash)

PowerShell 常用指令筆記

參考資料

MSDocs - Invoke-WebRequest