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

发布于 2024-11-29 02:23:07 字数 821 浏览 0 评论 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下的子对象,都允许它无限地查看孙对象。

问题:

如果我的脚本包含孙级或更高级别的文件,如何使我的脚本不将其视为空文件夹?

I have a PowerShell 2.0 script that I use to delete folders that have no files in them:

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

However, I noticed that there were a ton of errors when running the script. Namely:

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

"WHAT?!" I panicked. They should all be empty! I filter for only empty folders! Apparently that's not quite how the script is working. In this scenario a folder that has only folders as children, but files as grandchildren is considered empty of files:

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

In that case, PowerShell sees Folder1 as being empty and tries to delete it. The reason this puzzles me is because if I right-click on Folder1 in Windows Explorer It says that Folder1 has 1 folder and 1 file within it. Whatever is used to calculate the child objects underneath Folder1 from within Explorer allows it to see grandchild objects ad infinitum.

Question:

How can I make my script not consider a folder empty if it has files as grandchildren or beyond?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

摘星┃星的人 2024-12-06 02:23:07

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

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";

Here's a recursive function I used in a recent script...

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";
想你只要分分秒秒 2024-12-06 02:23:07

更新递归删除:

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

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

从此处 - 如何使用 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 。还要向 Remove-Item 添加一个 -whatif 以查看它是否会执行您期望的操作。

Updating for recursive deletion:

You can use a nested pipeline like below:

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

(from here - How to delete empty subfolders with PowerShell?)


Add a ($_.GetDirectories().Count -eq 0) condition too:

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

Here is a more succinct way of doing this though:

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

Note that you do not need the Foreach-Object while doing remove item. Also add a -whatif to the Remove-Item to see if it is going to do what you expect it to.

故人如初 2024-12-06 02:23:07

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

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

但是,我发现空文件夹的大小不是 0 而是 NULL。以下是我将使用的 PowerShell 脚本。它不是我自己的。相反,它来自 PowerShell MVP Richard Siddaway。您可以在 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

There were some issues in making this script, one of them being using this to check if a folder is empty:

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

However, I discovered that empty folders are not sized with 0 but rather NULL. The following is the PowerShell script that I will be using. It is not my own. Rather, it is from PowerShell MVP Richard Siddaway. You can see the thread that this function comes from over at 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
孤芳又自赏 2024-12-06 02:23:07

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

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}

You can use a recursive function for this. I actually have already written one:

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}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文