Pergunta

Eu tenho uma parte que é uma "gaveta de lixo" para os usuários finais. Eles são capazes de criar pastas e subpastas como acharem o ajuste. Preciso implementar um script para excluir arquivos criados com mais de 31 dias de idade.

Eu tenho que começou com PowerShell. Preciso acompanhar o script de exclusão de arquivos excluindo subpastas que agora estão vazias. Devido ao ninho de subpastas, preciso evitar a exclusão de uma subpasta vazia de arquivos, mas possui uma subpasta abaixo dele que contém um arquivo.

Por exemplo:

  • FILE3a tem 10 dias de idade. FILE3 tem 45 dias de idade.
  • Quero limpar a estrutura removendo arquivos com mais de 30 dias e excluir subpastas vazias.
C:\Junk\subfolder1a\subfolder2a\FILE3a

C:\Junk\subfolder1a\subfolder2a\subfolder3a

C:\Junk\subfolder1a\subfolder2B\FILE3b

Resultado desejado:

  • Excluir: FILE3b, subfolder2B & subfolder3a.
  • Sair: subfolder1a, subfolder2a, e FILE3a.

Eu posso limpar recursivamente os arquivos. Como faço para limpar as subpastas sem excluir subfolder1a? (A pasta "lixo" sempre permanecerá.)

Foi útil?

Solução

Eu faria isso em dois passes - excluindo os arquivos antigos primeiro e depois os diretos vazios:

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

Esse tipo de demos de operação O poder dos pipelines aninhados em PowerShell, que o segundo conjunto de comandos demonstra. Ele usa um pipeline aninhado para determinar recursivamente se algum diretório possui zero arquivos sob ele.

Outras dicas

No espírito da primeira resposta, aqui está a maneira mais curta de excluir os diretórios vazios:

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

A bandeira -force é necessária para os casos em que os diretórios têm pastas ocultas, como .svn

Isso classificará os subdiretórios antes dos diretórios dos pais que trabalham em torno do problema de diretório aninhado vazio.

dir -Directory -Recurse |
    %{ $_.FullName} |
    sort -Descending |
    where { !@(ls -force $_) } |
    rm -WhatIf

Adicionando ao último:

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

Isso o completará onde continuará pesquisando para remover qualquer pasta vazia sob o $ StartingPoint

Eu precisava de alguns recursos que amigam a empresa. Aqui está minha opinião.

Comecei com o código de outras respostas e adicionei um arquivo JSON com a lista de pastas original (incluindo contagem de arquivos por pasta). Removeu os diretórios vazios e registre -os.

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.

Para remover arquivos com mais de 30 dias:

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

(Basta remover o -whatif para realmente executar.)

Acompanhe com:

 get-childitem -recurse |
     ? {$_.GetType() -match "DirectoryInfo"} |
     ?{ $_.GetFiles().Count -eq 0 -and $_.GetDirectories().Count -eq 0 } |
     rm -whatif

Isso funcionou para mim.

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

$path = "C:\Some\Path"

Excluir arquivos mais antigos que o $limit:

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

Exclua todos os diretórios vazios deixados para trás depois de excluir os arquivos antigos:

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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top