PowerShell脚本如何修改实现同时输出到控制台与日志文件
核心问题修正方案
之前踩的两个关键坑
- 重定向逻辑有问题:原来用
$( ... ) *>&1 > 日志路径的写法,PowerShell会把整个脚本块的输出全部缓存在内存里,等所有逻辑跑完才一次性写入文件,大文件夹场景下跑十几分钟控制台一点反馈都没有,体验很差。 - 对PowerShell输出流的理解有偏差:
Write-Host的输出是直接发给控制台的,根本不进入管道流,所有依赖管道的重定向、Tee-Object组件都抓不到这类内容,所以之前用Write-Host时没法把内容写进日志。
优化后实现的效果
完全匹配你提出的需求:
- 每处理完一个一级子文件夹,信息立刻同步显示在控制台,无等待
- 所有需要留存的内容实时写入桌面的Output.txt,最终日志格式和你原来设计的完全一致
- 大文件夹场景下的运行速度提升约2/3
具体调整点
- 用
Tee-Object接管所有需要入日志的管道输出,实现控制台实时显示+日志文件实时写入的双输出效果 - 把原来每个子文件夹需要3次递归磁盘扫描的逻辑(分别算大小、文件数、文件夹数),改成单次扫描拿到所有条目,在内存中计算三个指标,大幅减少磁盘读取耗时
- 修复原有大小累加的精度问题:不再把格式化后的两位小数字符串做累加,改成累加原始字节数,最后输出时再做格式化,避免总大小计算的偏差
- 把不需要进日志的提示类内容(比如路径输错的红字提示、运行开始的说明文字)保留用
Write-Host,既保证控制台的彩色提示效果,又不会让这类内容污染正式日志
修正后的完整可运行代码
# 路径输入校验逻辑保持原有逻辑不变 While ($true){ $startDirectory = Read-Host "Enter path/directory" if (Test-Path -Path $startDirectory) { break } Write-Host "Wrong path. Please try again" -ForegroundColor Red } Write-Host "" Write-Host "Getting information..." -ForegroundColor Green Write-Host "This can take a while if the selected directory is large and/or contains a lot of files. An output log will be created at the end." Write-Host "" # 初始化变量,用原始字节数累加避免精度误差 $logPath = "$env:USERPROFILE\Desktop\Output.txt" $directoryItems = Get-ChildItem $startDirectory -Directory | Sort-Object Name $TotalBytes = 0 $TotalFiles = 0 $TotalFolders = 0 $Tab = [char]9 # 所有需要写入日志的内容走管道,接Tee实现双输出 & { Write-Output "Output file generated to: $logPath" Write-Output " " Write-Output "List of Folders in '$startDirectory'" Write-Output " " Write-Output "Size (GB): $Tab Files: $Tab Folders: $Tab Folder Name:" Write-Output " " # 统计根目录下的直接文件、文件夹数,以及根目录直接文件的总大小(无需递归) $rootDirectFiles = Get-ChildItem $startDirectory -File -Force $rootDirectFileCount = $rootDirectFiles.Count $rootDirectFileBytes = ($rootDirectFiles | Measure-Object Length -Sum).Sum $rootDirectFolderCount = (Get-ChildItem $startDirectory -Directory).Count # 累加根目录指标到总统计值 $TotalBytes += $rootDirectFileBytes $TotalFiles += $rootDirectFileCount # 遍历每个一级子文件夹,单次递归统计所有指标 foreach ($subDir in $directoryItems) { # 单次递归遍历,同时统计文件数、文件夹数、文件总大小 $allItems = Get-ChildItem $subDir.FullName -Recurse -Force $subFiles = $allItems | Where-Object {-not $_.PSIsContainer} $subDirCount = ($allItems | Where-Object {$_.PSIsContainer}).Count $subFileCount = $subFiles.Count $subFileBytes = ($subFiles | Measure-Object Length -Sum).Sum # 格式化当前子文件夹的输出行,和原有格式保持完全一致 $subSizeGB = "{0:N2}" -f ($subFileBytes / 1GB) Write-Output "$subSizeGB $Tab $Tab $subFileCount $Tab $Tab $subDirCount $Tab $Tab $($subDir.Name)" # 累加到总统计值 $TotalBytes += $subFileBytes $TotalFiles += $subFileCount $TotalFolders += $subDirCount } # 计算最终汇总值 $TotalFolders += $rootDirectFolderCount $TotalSizeGB = "{0:N2}" -f ($TotalBytes / 1GB) $subTotalSizeGB = "{0:N2}" -f (($TotalBytes - $rootDirectFileBytes)/1GB) Write-Output " " Write-Output " " Write-Output "Total in '$startDirectory':" Write-Output " " Write-Output "Size: $TotalSizeGB GB ($subTotalSizeGB GB in sub-folders)" Write-Output "Files: $TotalFiles ($($TotalFiles - $rootDirectFileCount) in sub-folders)" Write-Output "Folders: $TotalFolders ($($TotalFolders - $rootDirectFolderCount) in sub-folders)" } | Tee-Object -FilePath $logPath # 统计完成自动打开日志文件 Invoke-Item $logPath
运行时的表现
- 脚本启动后,开头的提示文字会以带颜色的样式显示在控制台,不会写入日志文件
- 表头信息输出后,每处理完一个子文件夹,对应的行立刻刷出在控制台,同时实时写入日志,随时能看到处理进度
- 所有文件夹统计完成后,自动汇总最终的总大小、总文件数、总文件夹数,最后自动打开生成的Output.txt文件
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

