【问题标题】:Powershell Script to delete files not in a list with progress barPowershell脚本用于删除不在带有进度条的列表中的文件
【发布时间】:2017-03-02 23:19:25
【问题描述】:

我有一个包含 .jpg 文件的文件夹。我将这些与访问数据库中的产品相关联。产品来源之一提供了这些 .jpg 文件,但它们不允许您轻松下载仅当前使用的图片。因此,我找到了一个 PowerShell 脚本来删除我不需要的文件。

$exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt
dir -rec M:\PhotoDirectory\PhotoFolder | Where-Object {$exclusions -notcontains $_.name } | Remove-Item

归功于@x0n Powershell script to delete files not specified in a list

而且效果很好!但问题是它需要很长时间,我有超过 180,000 个项目要搜索和删除。所以我想制作一个进度条,让我知道我在这个过程中走了多远。

所以经过一番搜索,我找到了一篇名为“使用进度条”的文章

问题是我不知道如何将两者混合在一起,但是我在这里做了一个尝试:

$exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt 
  1..100 | foreach-object {
    Write-Progress -Activity "Deleting Files" -Status "$_ %" -Id 1 -PercentComplete $_ -CurrentOperation "Deleting File $_"
       dir -rec M:\PhotoDirectory\PhotoFolder | Where-Object {$exclusions -notcontains $_.name } | Remove-Item
        }

然而,这似乎比原始脚本花费的时间更长,我不知道它是如何工作的,当我只需要删除 10-15 个文件时,我正在测试它。

我很可能缺少一些非常基本的东西但我真的很感激能帮助我理解这一点。

这里我添加了一个截图:

PowerShell Console

【问题讨论】:

    标签: powershell progress-bar delete-file


    【解决方案1】:

    然而,这似乎比原始脚本花费的时间更长

    那是因为您尝试枚举、过滤和删除文件 100 次 - 这显然是不必要的。

    您要做的是计算您在删除文件的过程中走了多远,然后将其作为您传递给Write-Progress 的百分比的基础。保持计数的最简单方法可能是使用常规的for 循环:

    注意:前两个示例非常通用,请转到底部查看将您的容量(约 180.000 个文件)考虑在内的示例。

    # Grab all the files you need to delete
    $exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt
    $filesToDelete = Get-ChildItem M:\PhotoDirectory\PhotoFolder -Recurse | Where-Object {$exclusions -notcontains $_.Name }
    
    for($i = 0; $i -lt $filesToDelete.Count; $i++){
        # calculate progress percentage
        $percentage = ($i + 1) / $filesToDelete.Count * 100
        Write-Progress -Activity "Deleting Files" -Status "Deleting File #$($i+1)/$($filesToDelete.Count)" -PercentComplete $percentage
        # delete file
        $filesToDelete[$i] |Remove-Item
    }
    # All done
    Write-Progress -Activity "Deleting Files" -Completed
    

    您可能想要用来表示百分比的另一个特征是删除的相对量(总字节数)。我们可以通过简单地跟踪我们需要删除总共多少字节以及到目前为止我们已经删除了多少来做到这一点:

    $exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt
    $filesToDelete = Get-ChildItem M:\PhotoDirectory\PhotoFolder -Recurse | Where-Object {$exclusions -notcontains $_.Name }
    $TotalSize = ($filesToDelete |Measure-Object -Property Length -Sum).Sum
    $BytesRemoved = 0
    
    foreach($file in $filesToDelete){
        $percentage = $BytesRemoved / $TotalSize * 100
        Write-Progress -Activity "Deleting Files" -Status "Deleted $BytesRemoved/$TotalSize bytes" -PercentComplete $percentage
        $file |Remove-Item
        $BytesRemoved += $file.Length
    }
    Write-Progress -Activity "Deleting Files" -Completed
    

    正如@MatthewWetmore 指出的那样,每次删除文件时调用Write-Progress 当然会产生一些开销。对于 180.000 个文件,当进度从 3.56325% 变为 3.56331% 时,您可能对更新 UI 不那么感兴趣

    您可以做的是使用for 循环以整个项目集的 1% 为增量进行计数,然后在每次迭代时删除整个文件范围:

    [int]$hundredthStep = $filesToDelete.Count / 100
    for($i = 0; $i -lt $filesToDelete.Count; $i += $hundredthStep){
        # calculate progress percentage
        $percentage = ($i + 1) / $filesToDelete.Count * 100
        Write-Progress -Activity "Deleting Files" -Status "Deleting File up to #$($i+1)/$($filesToDelete.Count)" -PercentComplete $percentage
        # delete file
        $filesToDelete[$i..($i + $hundredthStep - 1)] |Remove-Item
    }
    # All done
    Write-Progress -Activity "Deleting Files" -Completed
    

    【讨论】:

    • 如果要删除的文件数量非常多,他也会受益于不是每个文件都写入进度,而是每隔几个。例如,将计数除以 100,四舍五入到最接近的 int,然后将其用作计数器的模数。例如。对于 1-100 个文件,您将编写每个文件的进度。有 200 个,每隔一个文件。有 1000 个,每 10 个...
    • 此外,我还看到一棵非常大的树上的递归 get-item 非常慢。我对 get-item -recurse -directory 的运气更好,然后迭代地 get-item -file。我已经为此编写了变体以验证 OS VHD 或 WIM 内容。
    • “那是因为你试图枚举、过滤和删除文件 100 次——这显然是不必要的。”这当然是有道理的,因为我试图让它在整个脚本中运行 100 次,并给自己一个进度条来告诉我它什么时候完成重复。我喜欢它计算删除的总字节数的选项。我会尝试一下,然后带着我的发现回来。
    • @MatthewWetmore 好点,挪用第一个例子以 1% 的增量计数
    • @MatthewWetmore 也可以,但是你执行循环体 180000 次 vs 100 次 :-)
    【解决方案2】:

    你想做这样的事情(注意这是未经测试的,所以我把 -whatif 放在了删除 cmdlet 上,当你满意它工作正常时应该删除它):

    $exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt 
    $files = dir -rec M:\PhotoDirectory\PhotoFolder | Where-Object {$exclusions -notcontains $_.name } 
    
    $files | foreach-object {
        $num += 1    
        Write-Progress -Activity "Deleting Files" -Status "$_ %" -Id 1 -PercentComplete (($num / $files.count) * 100)  -CurrentOperation "Deleting File $($_.name)"
        $_ | Remove-Item -WhatIf
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-04
      相关资源
      最近更新 更多