Powershell Get-ChildItem 进度指示

问题描述 投票:0回答:1

是否可以为以下(或类似)命令显示任何类型的进度指示器?

$dir = 'C:\$Recycle.Bin\S-1-5-18\'
(Get-ChildItem -LiteralPath $dir -File -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum / 1GB

(将其输出通过管道传输到“

Powershell Get-ChildItem进度问题
”的其中一个答案中建议的%{Write-Output processing item: $_.fullname; $_}之类的东西 - 似乎不起作用。例如,

$dir = 'C:\$Recycle.Bin\S-1-5-18\'
(Get-ChildItem -LiteralPath $dir -File -Force -ErrorAction SilentlyContinue | %{Write-Output processing item: $_.fullname; $_} | Measure-Object -Property Length -Sum).Sum / 1GB

...除了最终结果(大小以 GB 为单位)之外,根本不产生任何输出。

背景

在我们的许多服务器上,

C:\$Recycle.Bin\S-1-5-18\
(“系统”帐户的回收站目录)包含数百万个文件,数百或数千个子目录(也可能包含大量文件),并且不断被填满速率为 1-3GB/天。

罪魁祸首是这些服务器上行为不当的“业务线”应用程序,它似乎将大量临时文件写入回收站。目前,不是可以选择阻止它或改变其行为。

我的首要任务是:

  1. 找出一种方法来智能地清空此回收站,也许基于项目年龄(例如,永久删除早于 NN 天的文件和子目录,并且仅在特定时间执行此操作 - 例如每天凌晨 1 点到 4 点之间)
  2. 弄清楚如何防止应用程序完全使用回收站 - 例如通过为此帐户/卷(
    NukeOnDelete
    NeedToPurge
    MaxCapacity
    )或强制永久删除文件的 GPO 设置注册表值。

第一部分,使用 Powershell 从回收站清除文件,似乎需要首先通过

Get-ChildItem
获取要删除的项目列表 - 这对于驻留在相当慢的磁盘上的大型目录来说需要很长很长时间。

有没有办法在通过管道传输到

Get-ChildItem
或类似命令时获取
Measure-Object
正在执行某些操作的指示符(例如,到目前为止它能够收集的项目数量)?

附注我认为这可能是可能的原因是因为

Get-ChildItem
本身(没有到
Measure-Object
的管道)立即开始输出。像 TreeSize 这样的实用程序似乎能够在“遍历”目录树和收集数据时显示进度。
dir /a/s C:\$Recycle.Bin\S-1-5-18\
也会立即开始输出,即使需要很长时间才能完成。当我们通过管道将其传输到
Measure-Object
或类似命令时,是否有机会获得进度指示器?

powershell windows-server get-childitem recycle-bin progress-indicator
1个回答
0
投票

也许这可能对您有帮助,本质上它使用

DirectoryInfo
中的 .NET API 和
Queue<T>
来遍历初始目录。这样做的好处是性能,并且您将能够在遍历目录时跟踪总长度。

$queue = [System.Collections.Generic.Queue[System.IO.DirectoryInfo]]::new()
$initialItem = Get-Item 'C:\$Recycle.Bin\S-1-5-18\' -ErrorAction Stop
$queue.Enqueue($initialItem)
$totalLength = 0

while ($queue.Count) {
    $current = $queue.Dequeue()

    $writeProgressSplat = @{
        Activity = 'Total Length: {0, 10} Gb' -f [Math]::Round($totalLength / 1gb, 2)
        Status   = "Processing: '{0}'" -f $current.FullName
    }

    Write-Progress @writeProgressSplat

    try {
        $enum = $current.EnumerateFileSystemInfos()
    }
    catch {
        # we can't enumerate this dir, add error handling here
        # or empty to ignore enumeration errors

        # dont remove this!
        continue
    }

    foreach ($item in $enum) {
        if ($item -is [System.IO.DirectoryInfo]) {
            $queue.Enqueue($item)
            continue
        }
        $totalLength += $item.Length
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.