删除早于 xx 天的文件

Delete files older than xx days

我需要以编程方式(最好使用 Powershell)从文件夹中删除一些超过给定天数的文件。

我已经编写了一个简单的脚本来执行此操作,但是我遇到的问题是,由于文件夹中的文件数量巨大,似乎甚至无法开始删除。

我正在寻找一种批量删除的方法。所以它可能会获取前 1000 个,删除,然后依此类推。

现在这个文件夹大概有几十万个文件,几乎无法遍历。

Param(
  [Parameter(Mandatory=$true)][string]$Path,
  [Parameter(Mandatory=$true)][string]$DaysToDelete
)

$limit = (Get-Date).AddDays($DaysToDelete)
$LogFile = "FileCleanupLog-$(Get-Date -f yyyyMMdd_HH_mm_ss).txt";

function Log-Message
{
   Param ([string]$logtext)
   Add-content $LogFile -value $logtext
}

If (-Not (Test-Path $Path))
{
    Write-Host "Invalid Path provided!" -ForegroundColor Red
    Exit
}

$files = Get-ChildItem -Path $Path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit }

If ($files.Count -GT 1) {
    $files | % {$directory=$_.DirectoryName;(Log-Message "Deleting File $directory$_");$_ } | Remove-Item -Force 
}

与其遍历所有文件并将标记为删除的文件存储在列表中,然后再次遍历列表中的每个文件,不如在找到它们时将每个文件通过管道传输到下一个命令。

所以替换这个:

$files = Get-ChildItem -Path $Path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit }

If ($files.Count -GT 1) {
    $files | % {$directory=$_.DirectoryName;(Log-Message "Deleting File $directory$_");$_ } | Remove-Item -Force 
}

像这样:

Get-ChildItem -Path $Path -Recurse -Force `
| Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } `
| % {
    $directory=$_.DirectoryName
    (Log-Message "Deleting File $directory$_")
    $_ } `
| Remove-Item -Force

要满足您批量删除 1000 个文件的条件,请使用以下方法。 select -first 1000 将导致它每次通过 while 循环时只删除 1000 个文件。

while($true){
    $files = Get-ChildItem -Path $Path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | select -first 1000
    If ($files.Count -GT 1) {
        $files | % {$directory=$_.DirectoryName;(Log-Message "Deleting File $directory$_");$_ } | Remove-Item -Force 
    } else {
        exit 
    }
}

我不知道这是否会更快——这取决于 PowerShell 是否足够智能以在找到前 1000 个文件后停止 get-childitem。

我不得不承认我对 robocopy 的工作方式有点误解。虽然它可以删除文件,但当被告知时,它仍然必须执行复制操作。所以这个建议最好在目标机器上 运行 而不是使用 UNC 路径。除了失望之外,我仍然认为这是一个可行的解决方案。这里最主要的是 robocopy 将 select 仅我们需要的文件而不进行任何 post 处理。

$sourceDirectory = "D:\temp\New folder"
$dummyDirectory = "D:\temp\trashbin"
$loggingFile = "D:\temp\FileCleanupLog-$(Get-Date -f yyyyMMdd_HH_mm_ss).txt"

# Build the dummy directory. It will be deleted in the end.
New-Item -Path $dummyDirectory -ItemType Directory | Out-Null

& robocopy.exe $sourceDirectory /njh /ndl /nc /njs /minage:$days /mov /e /ns /np /l | Set-Content $loggingFile

# Purge the dummy directory with all the content we don't want
Remove-Item -Path $dummyDirectory -Force -Confirm:$false -Recurse

这里是所有使用的开关所代表的。大多数是为了清理日志记录的输出。日志应该只有一个已删除的完整路径列表。这目前不会影响目录结构。如果需要,开关更改将解决此问题。您还会看到 /l 仅用于日志记录。您可以使用该开关来测试您想要的文件是否被删除。对于实际的生产测试,您需要将其删除。

/minage:N        Specifies the minimum file age (exclude files newer than N days or date).
/njh             Specifies that there is no job header.
/njs             Specifies that there is no job summary.
/l               Specifies that files are to be listed only (and not copied, deleted, or time stamped).
/mov             Moves files, and deletes them from the source after they are copied.
/ndl             Specifies that directory names are not to be logged.
/nc              Specifies that file classes are not to be logged.\
/np              Specifies that the progress of the copying operation (the number of files or directories copied so far) will not be displayed.

如果它不花时间在屏幕上显示数据,这也会执行得更快。这就是为什么我特意把 /np 放在那里。