Как удалить пустые подпапки с помощью PowerShell?
У меня есть доля, которая является "нежелательным ящиком" для конечных пользователей. Они могут создавать папки и подпапки по своему усмотрению. Мне нужно реализовать script для удаления файлов, созданных более 31 дня.
У меня это началось с Powershell. Мне нужно следить за удалением файла script, удалив подпапки, которые теперь пусты. Из-за вложенности вложенных папок мне нужно избегать удаления вложенной папки, свободной от файлов, но под ней находится подпапка, содержащая файл.
Например:
-
FILE3a
- 10 дней. FILE3
составляет 45 дней.
- Я хочу очистить структуру, удаляя файлы старше 30 дней, и удалять пустые подпапки.
C:\Junk\subfolder1a\subfolder2a\FILE3a
C:\Junk\subfolder1a\subfolder2a\subfolder3a
C:\Junk\subfolder1a\subfolder2B\FILE3b
Желаемый результат:
- Удалить:
FILE3b
, subfolder2B
и subfolder3a
.
- Оставьте:
subfolder1a
, subfolder2a
и FILE3a
.
Я могу рекурсивно очищать файлы. Как очистить подпапки, не удаляя subfolder1a
? (Папка "Нежелательная" всегда будет оставаться.)
Ответы
Ответ 1
Я бы сделал это за два прохода - сначала удалив старые файлы, а затем пустые директории:
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
Этот тип операций демонстрирует мощь вложенных конвейеров в PowerShell, которые демонстрирует второй набор команд. Он использует вложенный конвейер для рекурсивного определения, есть ли в нем каталог с нулевыми файлами.
Ответ 2
В духе первого ответа, вот кратчайший способ удаления пустых каталогов:
ls -recurse | where {[email protected](ls -force $_.fullname)} | rm -whatif
Флаг -force необходим для случаев, когда каталоги имеют скрытые папки, например .svn
Ответ 3
Добавление к последнему:
while (Get-ChildItem $StartingPoint -recurse | where {[email protected](Get-ChildItem -force $_.fullname)} | Test-Path) {
Get-ChildItem $StartingPoint -recurse | where {[email protected](Get-ChildItem -force $_.fullname)} | Remove-Item
}
Это сделает его завершенным, когда он продолжит поиск, чтобы удалить все пустые папки под $StartingPoint
Ответ 4
Это будет сортировать подкаталоги перед родительскими каталогами, работающими вокруг проблемы с пустым вложенным каталогом.
dir -Directory -Recurse |
%{ $_.FullName} |
sort -Descending |
where { [email protected](ls -force $_) } |
rm -WhatIf
Ответ 5
Чтобы удалить файлы старше 30 дней:
get-childitem -recurse |
? {$_.GetType() -match "FileInfo"} |
?{ $_.LastWriteTime -lt [datetime]::now.adddays(-30) } |
rm -whatif
(Просто удалите -whatif
для фактического выполнения.)
Следуйте за:
get-childitem -recurse |
? {$_.GetType() -match "DirectoryInfo"} |
?{ $_.GetFiles().Count -eq 0 -and $_.GetDirectories().Count -eq 0 } |
rm -whatif
Ответ 6
Мне нужны были удобные для пользователя функции. Вот мой прием.
Я начал с кода из других ответов, а затем добавил файл JSON с исходным списком папок (включая количество файлов в папке). Удалены пустые каталоги и запишите их.
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.
Ответ 7
Это сработало для меня.
$limit = (Get-Date).AddDays(-15)
$path = "C:\Some\Path"
Удалите файлы старше $limit
:
Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force
Удалите все оставшиеся пустые каталоги после удаления старых файлов:
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