You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化因Get-ChildItem耗尽内存的PowerShell共享统计脚本

优化PowerShell共享统计脚本解决内存耗尽问题

原脚本的核心问题是Get-ChildItem -Recurse的结果被完整存入$GetObjectInfo变量,大型共享中的海量文件/文件夹对象会直接耗尽系统内存。以下是针对这个问题的具体优化方案:

核心优化思路

  • 流式处理,不缓存全部对象:通过管道直接传递Get-ChildItem的输出,处理完单个对象就释放内存,避免一次性加载所有内容。
  • 单次遍历完成多维度统计:在一次遍历中同时计算文件数、文件夹数和总大小,避免多次重复遍历对象集合,减少内存占用和运行时间。
  • 精简不必要的对象调用:合并重复的文件属性读取操作,减少系统调用开销。

优化后的完整脚本

$ScopeName     = Read-Host "Enter scope name to gather data on"
$SavePath      = Read-Host "Path to save results and log to"
$SaveCSVPath   = "$SavePath\ShareData.csv"
$TranscriptLog = "$SavePath\Transcript.log"

Write-Host
Start-Transcript -Path $TranscriptLog

$StartTime = Get-Date
$Start     = $StartTime.DateTime

$Exclusions = { $_.Description -ne "Remote Admin" -and $_.Description -ne "Default Share" -and $_.Description -ne "Remote IPC" }
$FileShares = Get-SmbShare -ScopeName $ScopeName | Where-Object $Exclusions
$Count      = $FileShares.Count
Write-Host
Write-Host "Gathering data for $Count shares" -ForegroundColor Green
Write-Host
Write-Host "Results will be saved to $SaveCSVPath" -ForegroundColor Green
Write-Host

foreach ($FileShare in $FileShares) {
    $ShareName = $FileShare.Name
    $Path      = $FileShare.Path

    Write-Host "Working on: $ShareName - $Path" -ForegroundColor Yellow

    # 初始化统计变量
    $totalSize = 0
    $fileCount = 0
    $folderCount = 0

    # 流式遍历文件和文件夹,不缓存全部对象
    Get-ChildItem -Path $Path -Recurse -Force -ErrorAction SilentlyContinue | ForEach-Object {
        if ($_.PSIsContainer) {
            $folderCount++
        } else {
            $fileCount++
            # 累加文件大小,跳过无长度的文件(如快捷方式)
            if ($null -ne $_.Length) {
                $totalSize += $_.Length
            }
        }
    }

    # 计算不同单位的大小
    $ObjectSizeMB = "{0:N2}" -f ($totalSize / 1MB)
    $ObjectSizeGB = "{0:N2}" -f ($totalSize / 1GB)
    $ObjectSizeTB = "{0:N2}" -f ($totalSize / 1TB)

    # 一次性读取共享路径的属性,避免重复调用
    $shareProps = Get-ItemProperty -Path $Path
    $ACL = Get-Acl -Path $Path

    $Table = [PSCustomObject]@{
        'ScopeName'          = $FileShare.ScopeName
        'Sharename'          = $ShareName
        'SharePath'          = $Path
        'Owner'              = $ACL.Owner
        'Permissions'        = $ACL.AccessToString
        'LastAccess'         = $shareProps.LastAccessTime
        'LastWrite'          = $shareProps.LastWriteTime
        'Size (MB)'          = $ObjectSizeMB
        'Size (GB)'          = $ObjectSizeGB
        'Size (TB)'          = $ObjectSizeTB
        'Total File Count'   = $fileCount
        'Total Folder Count' = $folderCount
        'Total Item Count'   = ($fileCount + $folderCount)
    }

    $Table | Export-CSV -Path $SaveCSVPath -Append -NoTypeInformation 
}

$EndTime = Get-Date
$End     = $EndTime.DateTime

Write-Host
Write-Host "Script start time: $Start" -ForegroundColor Green
Write-Host "Script end time: $End" -ForegroundColor Green

Write-Host
$ElapsedTime = $EndTime - $StartTime
Write-Host "Elapsed time: $($ElapsedTime.Days) Days $($ElapsedTime.Hours) Hours $($ElapsedTime.Minutes) Minutes $($ElapsedTime.Seconds) Seconds $($ElapsedTime.Milliseconds) Milliseconds" -ForegroundColor Cyan

Write-Host
Write-Host "Results saved to $SaveCSVPath" -ForegroundColor Green

Write-Host
Write-Host "Transcript saved to $TranscriptLog" -ForegroundColor Green

Write-Host
Stop-Transcript

关键优化点说明

  1. 移除全量对象缓存:不再将Get-ChildItem的结果存入变量,而是直接通过ForEach-Object逐个处理,每个对象处理完成后立即被垃圾回收,不会占用大量内存。
  2. 单次遍历完成统计:在ForEach-Object中同时统计文件数、文件夹数和总大小,避免了原脚本中多次过滤$GetObjectInfo的重复操作,大幅提升效率。
  3. 合并属性读取:将原脚本中两次Get-ItemProperty调用合并为一次,减少系统IO开销。
  4. 空值判断:对文件长度做了空值判断,避免因特殊文件(如快捷方式、零字节文件)导致的计算错误。

内容的提问来源于stack exchange,提问作者ShaynG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 05:36:18