Назад | Перейти на главную страницу

Скрипт Powershell для удаления самых старых файлов (не относительно текущей даты)

я НЕ хотите «удалить файлы старше X дней». Если бы я хотел это сделать, я бы просто выбрал один из тысяч сценариев, которые уже были написаны для этой цели, и не стал бы задавать такой тривиальный вопрос о ServerFault.

я ДЕЛАТЬ хотите удалить все файлы, кроме N последних, в определенной папке.

Фон: удаленная система настроена на выгрузку периодических архивных файлов в общую папку на сервере Windows. Эти файлы имеют соглашение об именах ГГГГММДД-ччмм.ext. В случае сбоя процесса архивирования я не хочу, чтобы сценарий очистки удалял файлы только потому, что они старше, чем на много дней. Невозможно настроить удаленную систему на очистку файлов в процессе архивирования.

Так, например, при запуске сценария может быть 10 файлов, может быть 7 файлов, может быть 5 файлов в папке. Мне нужно всегда хранить как минимум 5 самых последних, независимо от того, сколько им лет.

Можно ли это сделать с помощью PowerShell?

РЕДАКТИРОВАТЬ: желательно игнорировать файлы или папки, не соответствующие соглашению об именах. Другие файлы и папки не следует удалять, и они не должны сбивать с толку скрипт (в результате остается менее 5 архивных файлов).

Использование: yourScript.ps1 -Path path \ to \ run \ against [-NumberToSave N]

param([String]$Path,[Int32]$NumberToSave=5)

$items = Get-ChildItem "$Path\*.ext" |
    Where-Object Name -match "\d\d\d\d\d\d\d\d-\d\d\d\d\.ext" |
    Sort-Object Name -Descending

if ($NumberToSave -lt $items.Count)
{
    $items[$NumberToSave..($items.Count-1)] | Remove-Item
}

Я не ожидаю, что это действительно лучше, чем у @John, я просто сделал это, чтобы попробовать параметры, регулярное выражение, а не использовать цикл. Сопоставление с регулярным выражением действительно имеет возможное преимущество в исключении других файлов с .ext, которые не соответствуют формату (например, 20130504-1200.txt.ext, 20.ext), но сомнительно, что это применимо.

Я был поражен, узнав, что если $ NumberToSave = $ items.Count, тогда требуется оператор if, иначе его бы там не было. Технически:

$items[$numberToSave..$items.Count] | Remove-Item 

работает нормально (PowerShell, похоже, не вызывает ошибки, если вы ссылаетесь за пределы массива, он просто обрабатывает и игнорирует его?), но это казалось потенциально запутанным.

$n = x

$items = Get-ChildItem path_to_folder\*.ext

$items | 
  Sort-Object Name -Descending | 
  Select-Object -Last ($items.count - $n) | 
  Foreach-Object { Remove-Item $_ }

Друг предоставил этот сценарий:

# Defines how many files you want to keep?
$Keep = 5

# Specifies file mask
$FileMask = "*.ext"

# Defines base directory path
$Path = "F:\path\to\backups\"

# Creates a full path plus file mask value
$FullPath = $Path + $FileMask

# Creates an array of all files of a file type within a given folder, reverse sort.
$allFiles = @(Get-ChildItem $FullPath) | SORT Name -descending 

# Checks to see if there is even $Keep files of the given type in the directory.
If ($allFiles.count -gt $Keep) {

    # Creates a new array that specifies the files to delete, a bit ugly but concise.
    $DeleteFiles = $allFiles[$($allFiles.Count - ($allFiles.Count - $Keep))..$allFiles.Count]

    # ForEach loop that goes through the DeleteFile array
    ForEach ($DeleteFile in $DeleteFiles) {

        # Creates a full path and delete file value
        $dFile = $Path + $DeleteFile.Name

        # Deletes the specified file
        Remove-Item $dFile
    }
}
# Get all the items in `C:\Archive`
Get-ChildItem -Path 'C:\Archive' |

    # Skip directories
    Where-Object { -not $_.PsIsContainer } |

    # Only get files that match YYYYMMDD-HHMM.ext format
    Where-Object { $_.Name -match '\d{8}-\d{4}.ext' } |

    # Sort them by name, from most recent to oldest
    Sort-Object -Descending -Property Name |

    # Keep the first five items
    Select-Object -Skip 5 |

    Remove-Item -WhatIf

Я делал это в Bash раньше, и вы, возможно, сможете перевести это в PowerShell. Лично я администратор Linux и недостаточно разбираюсь в Windows / PowerShell, чтобы делать это сам.

#!/bin/bash

# Directory with backups in need of cleaning
bkps_dir="/opt/bkps/hosting.madyork.com"

# Make sure that there are at least 7 days worth of backups to avoid removing
#   the only backups left.
if [ "$(/bin/find "${bkps_dir}" -maxdepth 1 -type d | /usr/bin/wc -l)" -lt 8 ]; then
    echo "Less than 8 backups found!"
    echo "Will not delete anything!"
    echo "Exiting..."
    exit 1
fi

/bin/find "${bkps_dir}" -maxdepth 1 -type d -mtime +7 -print0 | /usr/bin/xargs -0 /bin/rm -rf

Извините, что я не мог быть более полезным.

Изменить: я также разместил это здесь на случай, если администратору Linux понадобится аналогичная информация.