PowerShell: поиск и удаление папок, в которых нет файлов или дочерних папок - PullRequest
3 голосов
/ 12 августа 2011

У меня есть сценарий 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 как пустую и пытается удалить ее. Причина, по которой меня это озадачивает, заключается в том, что если я щелкну правой кнопкой мыши на Folder1 в проводнике Windows, он скажет, что в Folder1 есть 1 папка и 1 файл. Все, что используется для вычисления дочерних объектов под Folder1 из Проводника, позволяет ему видеть объекты внуков до бесконечности.

Вопрос:

Как я могу сделать так, чтобы в моем скрипте папка не считалась пустой, если в нем есть файлы внуков или старше?

Ответы [ 4 ]

3 голосов
/ 12 августа 2011

Обновление для рекурсивного удаления:

Вы можете использовать вложенный конвейер, как показано ниже:

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 при удалении элемента. Также добавьте -whatif к Remove-Item, чтобы посмотреть, будет ли он делать то, что вы ожидаете.

2 голосов
/ 24 августа 2011

Были некоторые проблемы при создании этого скрипта, одна из которых использовала его, чтобы проверить, пуста ли папка:

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

Однако я обнаружил, что пустые папки имеют размер не 0, а NULL. Ниже приведен сценарий PowerShell, который я буду использовать. Это не мое собственное. Скорее, это от PowerShell MVP Ричард Сиддавей . Вы можете увидеть поток, из которого поступила эта функция, в этом потоке на 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
2 голосов
/ 12 августа 2011

Вот рекурсивная функция, которую я использовал в недавнем скрипте ...

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";
1 голос
/ 12 августа 2011

Вы можете использовать рекурсивную функцию для этого.Я на самом деле уже написал один:

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}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...