Cómo eliminar subcarpetas vacías con PowerShell?


Tengo un recurso compartido que es un "cajón de basura" para los usuarios finales. Son capaces de crear carpetas y subcarpetas como mejor les parezca. Necesito implementar un script para eliminar archivos creados con más de 31 días de antigüedad.

He empezado con Powershell. Necesito hacer un seguimiento del script de eliminación de archivos eliminando subcarpetas que ahora están vacías. Debido al anidamiento de subcarpetas, necesito evitar eliminar una subcarpeta que está vacía de archivos, pero tiene una subcarpeta debajo de ella que contiene una file.

Por ejemplo:

  • FILE3a tiene 10 días. FILE3 tiene 45 días.
  • Quiero limpiar la estructura eliminando archivos de más de 30 días y eliminar subcarpetas vacías.
C:\Junk\subfolder1a\subfolder2a\FILE3a

C:\Junk\subfolder1a\subfolder2a\subfolder3a

C:\Junk\subfolder1a\subfolder2B\FILE3b

Resultado deseado:

  • Suprimir: FILE3b, subfolder2B & subfolder3a.
  • Licencia: subfolder1a, subfolder2a, y FILE3a.

Puedo limpiar recursivamente los archivos. ¿Cómo puedo limpiar las subcarpetas sin eliminar subfolder1a? (La carpeta "Basura" siempre permanecer.)

Author: Tshepang, 2009-10-16

7 answers

Haría esto en dos pasadas - borrando primero los archivos antiguos y luego los dirs vacíos:

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

Este tipo de operación muestra la potencia de las canalizaciones anidadas en PowerShell que el segundo conjunto de comandos demuestra. Utiliza una canalización anidada para determinar recursivamente si algún directorio tiene cero archivos debajo de él.

 42
Author: Keith Hill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-22 15:13:29

En el espíritu de la primera respuesta, aquí está el camino más corto para eliminar los directorios vacíos:

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

El indicador-force es necesario para los casos en que los directorios tienen carpetas ocultas, como .svn

 9
Author: Bogdan Calmac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-20 18:29:46

Esto ordenará los subdirectorios antes de que los directorios padres trabajen alrededor del problema del directorio anidado vacío.

dir -Directory -Recurse |
    %{ $_.FullName} |
    sort -Descending |
    where { !@(ls -force $_) } |
    rm -WhatIf
 4
Author: Doug Coburn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-17 16:23:25

Añadiendo al último:

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

Esto lo hará completo donde continuará buscando para eliminar cualquier carpeta vacía bajo el Start StartingPoint

 3
Author: bbo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-15 14:47:38

Necesitaba algunas características empresariales. Aquí está mi opinión.

Comencé con código de otras respuestas, luego agregué un archivo JSON con la lista de carpetas original (incluido el recuento de archivos por carpeta). Se eliminaron los directorios vacíos y registrarlos.

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.
 2
Author: yzorg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-14 16:59:18

Para eliminar archivos de más de 30 días:

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

(Simplemente elimine el -whatif para realizar realmente.)

Seguir con:

 get-childitem -recurse |
     ? {$_.GetType() -match "DirectoryInfo"} |
     ?{ $_.GetFiles().Count -eq 0 -and $_.GetDirectories().Count -eq 0 } |
     rm -whatif
 2
Author: John Weldon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-14 19:01:55

Esto funcionó para mí.

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

$path = "C:\Some\Path"

Eliminar archivos anteriores a la $limit:

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

Elimine los directorios vacíos que queden después de eliminar los archivos antiguos:

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
 1
Author: ritikaadit2,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-17 14:10:32