PowerShell:查找并删除其中没有文件或子文件夹中的文件夹

时间:2011-08-12 00:27:43

标签: windows powershell powershell-v2.0

我有一个PowerShell 2.0脚本,用于删除其中没有文件的文件夹:

dir 'P:\path\to\wherever' -recurse | Where-Object { $_.PSIsContainer } | Where-Object { $_.GetFiles().Count -eq 0 } | foreach-object { remove-item $_.fullname -recurse}

但是,我注意到运行脚本时出现了大量错误。即:

Remove-Item : Directory P:\path\to\wherever cannot be removed because it is not empty.

“什么?!” 我惊慌失措。他们应 所有 为空!我只过滤空文件夹!显然这不是脚本的工作方式。在这种情况下,只有文件夹作为子文件夹但文件作为孙子文件的文件夹被视为空文件:

Folder1 (no files - 1 folder) \ Folder 2 (one file)

在这种情况下,PowerShell将Folder1视为空并尝试删除它。这让我感到困惑的原因是因为如果我在Windows资源管理器中右键单击Folder1它会说Folder1有1个文件夹和1个文件。无论用于从资源管理器中计算Folder1下面的子对象,它都可以无限制地查看孙子对象。

问题:

如果我的脚本文件是孙子孙女或更高版本,怎么能让我的脚本不考虑文件夹为空?

4 个答案:

答案 0 :(得分:3)

更新递归删除:

您可以使用如下所示的嵌套管道:

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

(从这里 - How to delete empty subfolders with PowerShell?


也添加($_.GetDirectories().Count -eq 0)条件:

dir path -recurse | Where-Object { $_.PSIsContainer } | Where-Object { ($_.GetFiles().Count -eq 0) -and ($_.GetDirectories().Count -eq 0) } | Remove-Item

这是一种更简洁的方式:

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

请注意,在执行删除项目时,您不需要Foreach-Object。同时在-whatif添加Remove-Item,看看它是否会按预期执行。

答案 1 :(得分:2)

这是我在最近的脚本中使用的递归函数......

function DeleteEmptyDirectories {
  param([string] $root)

  [System.IO.Directory]::GetDirectories("$root") |
    % {
      DeleteEmptyDirectories "$_";
      if ([System.IO.Directory]::GetFileSystemEntries("$_").Length -eq 0) {
        Write-Output "Removing $_";
        Remove-Item -Force "$_";
      }
    };
}

DeleteEmptyDirectories "P:\Path\to\wherever";

答案 2 :(得分:2)

制作此脚本时遇到一些问题,其中一个正在使用它来检查文件夹是否为空:

{!$_.PSIsContainer}).Length -eq 0

但是,我发现空文件夹的大小不是0而是NULL。以下是我将使用的PowerShell脚本。我自己 。相反,它来自PowerShell MVP Richard Siddaway。您可以在this thread on PowerShell.com找到此函数的主题。

function remove-emptyfolder {
 param ($folder)

 foreach ($subfolder in $folder.SubFolders){

 $notempty = $false
 if (($subfolder.Files | Measure-Object).Count -gt 0){$notempty = $true}
 if (($subFolders.SubFolders  | Measure-Object).Count -gt 0){$notempty = $true}
 if ($subfolder.Size -eq 0 -and !$notempty){
   Remove-Item -Path $($subfolder.Path) -Force -WhatIf
 }
 else {
  remove-emptyfolder $subfolder
 }

}

}

$path = "c:\test"
$fso = New-Object -ComObject "Scripting.FileSystemObject"

$folder = $fso.GetFolder($path)
remove-emptyfolder $folder

答案 3 :(得分:1)

您可以使用递归函数。我其实已经写了一篇:

cls

$dir = "C:\MyFolder"

Function RecurseDelete()
{
    param   (
            [string]$MyDir
            )

    IF (!(Get-ChildItem -Recurse $mydir | Where-Object {$_.length -ne $null}))
        {
            Write-Host "Deleting $mydir"
            Remove-Item -Recurse $mydir
        }
    ELSEIF (Get-ChildItem $mydir | Where-Object {$_.length -eq $null})
        {
            ForEach ($sub in (Get-ChildItem $mydir | Where-Object {$_.length -eq $null}))
            {
                Write-Host "Checking $($sub.fullname)"
                RecurseDelete $sub.fullname
            }   
        }
    ELSE
        {
            IF (!(Get-ChildItem $mydir))
                {
                    Write-Host "Deleting $mydir"
                    Remove-Item $mydir
                }

        }
}

IF (Test-Path $dir) {RecurseDelete $dir}