29

我有一个对最终用户来说是“垃圾抽屉”的共享。他们可以根据需要创建文件夹和子文件夹。我需要实现一个脚本来删除创建超过 31 天的文件。

我从 Powershell 开始。我需要通过删除现在为空的子文件夹来跟进文件删除脚本。由于子文件夹的嵌套,我需要避免删除一个没有文件的子文件夹,但它下面有一个包含文件的子文件夹。

例如:

  • FILE3a是 10 天大。 FILE345 天。
  • 我想清理结构删除超过 30 天的文件,并删除空子文件夹。
C:\Junk\subfolder1a\subfolder2a\FILE3a

C:\Junk\subfolder1a\subfolder2a\subfolder3a

C:\Junk\subfolder1a\subfolder2B\FILE3b

期望的结果:

  • 删除:FILE3b, subfolder2B& subfolder3a
  • 离开:subfolder1asubfolder2aFILE3a

我可以递归地清理文件。如何清理子文件夹而不删除subfolder1a?(“垃圾”文件夹将始终保留。)

4

7 回答 7

46

我将分两遍执行此操作-先删除旧文件,然后再删除空目录:

Get-ChildItem -recurse | Where {!$_.PSIsContainer -and `
$_.LastWriteTime -lt (get-date).AddDays(-31)} | Remove-Item -whatif

Get-ChildItem -recurse | Where {$_.PSIsContainer -and `
@(Get-ChildItem -Lit $_.Fullname -r | Where {!$_.PSIsContainer}).Length -eq 0} |
Remove-Item -recurse -whatif

这种类型的操作演示了第二组命令演示的 PowerShell 中嵌套管道的强大功能。它使用嵌套管道递归地确定任何目录下是否有零个文件。

于 2009-10-15T22:56:09.000 回答
9

本着第一个答案的精神,这是删除空目录的最短方法:

ls -recurse | where {!@(ls -force $_.fullname)} | rm -whatif

当目录具有隐藏文件夹时需要 -force 标志,例如 .svn

于 2010-11-20T18:29:46.267 回答
5

这将在解决空嵌套目录问题的父目录之前对子目录进行排序。

dir -Directory -Recurse |
    %{ $_.FullName} |
    sort -Descending |
    where { !@(ls -force $_) } |
    rm -WhatIf
于 2015-07-31T22:20:24.913 回答
3

添加到最后一个:

while (Get-ChildItem $StartingPoint -recurse | where {!@(Get-ChildItem -force $_.fullname)} | Test-Path) {
    Get-ChildItem $StartingPoint -recurse | where {!@(Get-ChildItem -force $_.fullname)} | Remove-Item
}

这将使其完成,它将继续搜索以删除 $StartingPoint 下的任何空文件夹

于 2012-05-15T14:47:38.527 回答
2

要删除超过 30 天的文件:

get-childitem -recurse |
    ? {$_.GetType() -match "FileInfo"} |
    ?{ $_.LastWriteTime -lt [datetime]::now.adddays(-30) }  |
    rm -whatif

(只需删除-whatif实际执行。)

跟进:

 get-childitem -recurse |
     ? {$_.GetType() -match "DirectoryInfo"} |
     ?{ $_.GetFiles().Count -eq 0 -and $_.GetDirectories().Count -eq 0 } |
     rm -whatif
于 2009-10-15T22:37:48.237 回答
2

我需要一些对企业友好的功能。这是我的看法。

我从其他答案的代码开始,然后添加了一个带有原始文件夹列表的 JSON 文件(包括每个文件夹的文件数)。删除空目录并记录它们。

https://gist.github.com/yzorg/e92c5eb60e97b1d6381b

param (
    [switch]$Clear
)

# if you want to reload a previous file list
#$stat = ConvertFrom-Json (gc dir-cleanup-filecount-by-directory.json -join "`n")

if ($Clear) { 
    $stat = @() 
} elseif ($stat.Count -ne 0 -and (-not "$($stat[0].DirPath)".StartsWith($PWD.ProviderPath))) {
    Write-Warning "Path changed, clearing cached file list."
    Read-Host -Prompt 'Press -Enter-'
    $stat = @() 
}

$lineCount = 0
if ($stat.Count -eq 0) {
    $stat = gci -Recurse -Directory | %{  # -Exclude 'Visual Studio 2013' # test in 'Documents' folder

        if (++$lineCount % 100 -eq 0) { Write-Warning "file count $lineCount" }

        New-Object psobject -Property @{ 
            DirPath=$_.FullName; 
            DirPathLength=$_.FullName.Length;
            FileCount=($_ | gci -Force -File).Count; 
            DirCount=($_ | gci -Force -Directory).Count
        }
    }
    $stat | ConvertTo-Json | Out-File dir-cleanup-filecount-by-directory.json -Verbose
}

$delelteListTxt = 'dir-cleanup-emptydirs-{0}-{1}.txt' -f ((date -f s) -replace '[-:]','' -replace 'T','_'),$env:USERNAME

$stat | 
    ? FileCount -eq 0 | 
    sort -property @{Expression="DirPathLength";Descending=$true}, @{Expression="DirPath";Descending=$false} |
    select -ExpandProperty DirPath | #-First 10 | 
    ?{ @(gci $_ -Force).Count -eq 0 } | %{
        Remove-Item $_ -Verbose # -WhatIf  # uncomment to see the first pass of folders to be cleaned**
        $_ | Out-File -Append -Encoding utf8 $delelteListTxt
        sleep 0.1
    }

# ** - The list you'll see from -WhatIf isn't a complete list because parent folders
#      might also qualify after the first level is cleaned.  The -WhatIf list will 
#      show correct breath, which is what I want to see before running the command.
于 2014-03-14T16:47:54.097 回答
1

这对我有用。

$limit = (Get-Date).AddDays(-15) 

$path = "C:\Some\Path"

删除早于$limit:

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

删除旧文件后留下的所有空目录:

Get-ChildItem -Path $path -Recurse -Force | Where-Object { $_.PSIsContainer -and (Get-ChildItem -Path $_.FullName -Recurse -Force | Where-Object { !$_.PSIsContainer }) -eq $null } | Remove-Item -Force -Recurse
于 2016-08-17T13:13:03.287 回答