none
Нужен скрипт PowerShell. Для работы с большим количеством архивов. RRS feed

  • Вопрос

  • Коллеги подскажите есть аналогичное задание.

    1. Необходимо чтобы в папке c:\temp лежали архивы за текущий месяц.

    2. В конце месяца или в начале следующего из всех архивов оставались бы архивы только за 1 число месяца (прошедшего соответсвенно) если такого архива нет, то ближайший к нему с обеих сторон.

    3. сейчас есть архивы в этой папке аж за 2012 год.

    вот как бы мне их разформировать согласно задаче, можно даже создавать папки скажем с именем месяца и туда складывать именно 1 архив. вот не знаю

    Пробовал сдешнюю разработку с распознаванием дат, у меня почемуто сам скрипт пытаеться удалить все файлы старше 1 дня хотя дата их изменения явно совпадает с последним днем прошлого месяца. в чем может быть загвоздка помогите. спасибо за ранее.

    16 апреля 2014 г. 11:19

Ответы

  • # Текущий месяц
    $fdate = (Get-Date -Day 1).Date
    # Из $fdate вычитаем 12 месяцев
    $lltw = $fdate.AddMonths(-12)
    
    # Получаем файлы,которые созданы в интервале $lltw и $fdate, и удаляем те что старше
    $files = Get-ChildItem C:\temp | Where {!$_.PsIsContainer -and $_.LastWriteTime -lt $fdate} | Foreach {
    	if($_.LastWriteTime -lt $lltw) {
    		Remove-Item $_.FullName -Force -Recurse
    	}
    	else {
    		$_
    	}
    }
    
    # Группируем по названию базы
    $gr = $files | Group {$_.BaseName.split("_")[0]}
    
    $gr | Foreach {
    	# Группируем по месяцам, если в месяце 1 архив, то пропускаем. Далее ищем за 1-ое число, если нет, то берем 
    	# старший файл
    	$_.Group | Group {$_.LastWriteTime.Date.ToString("MMyyyy")} | Where {$_.Count -gt 1} | Foreach {
    		$rem  = $_.Group | Sort LastWriteTime
    		if($rem[0].LastWriteTime.Date.ToString("dd") -eq "01") {
    			$rem | Where {$_.LastWriteTime.Date.ToString("dd") -ne "01"} | Remove-Item -Force -Recurse
    		}
    		else {
    			$rem | Sort -Descending | Select -Skip 1 | Remove-Item -Force -Recurse
    		}
    	}
    }	

    • Помечено в качестве ответа HeartlesSpb 17 апреля 2014 г. 5:44
    17 апреля 2014 г. 5:33
    Отвечающий
  • Где:

    Remove-Item $_.FullName -Force -Recurse

    Заменить на:

    Move-Item $_.FullName -Destination $dest

    Где:

    Remove-Item -Force -Recurse

    Заменить на:

    Move-Item -Destination $dest

    • Помечено в качестве ответа HeartlesSpb 17 апреля 2014 г. 6:29
    17 апреля 2014 г. 6:21
    Отвечающий
  • cls
    #Задаем переменные путей 1 путь где хпраняться архивы
    #2 место откуда в последсвие будем удалять все ненужное
    $path = "C:\Test_script\1"
    #папка сохранёных архивов, туда будут перемещаться архивы которые не попадают в переуд сравнения
    $d = "C:\Test_script\2"
    # Задаем переменные дат. 
    # 30 дней назад от текущей даты.
    $Rdate = (Get-Date).adddays(-30)
    # Получаем список файлов старше 30 дней
    $files = Get-ChildItem $path | Where {!$_.PsIsContainer -and $_.LastWriteTime -lt $rdate} 
    # Группируем по названию базы
    # Группируем файлы в массиве по имени убирая все что правее 4 в имени.
    $gr = $files | Group {$_.BaseName.split("4")[0]}
    # после групировке запуская пофайловую проверку.
    $gr | Foreach {
        # в группе проверяем удаленность от 1 числа прошлого месяца, пропускаем 1 попавшийся остальные удаляем
        $_.Group |%{Add-Member -type NoteProperty -InputObject $_ -name Seconds -value $([math]::abs((([datetime]$_.lastwritetime) - ((get-date -day 1).AddMonths(-1).date)).TotalSeconds)) -force}
                        $_.group|sort -Property Seconds|select -Skip 1 | move-item -Destination $d 
                }

    С уважением HeartlesSpb.

    • Помечено в качестве ответа HeartlesSpb 21 мая 2014 г. 9:28

Все ответы

  • Коллеги подскажите есть аналогичное задание.

    1. Необходимо чтобы в папке c:\temp лежали архивы за текущий месяц.

    2. В конце месяца или в начале следующего из всех архивов оставались бы архивы только за 1 число месяца (прошедшего соответсвенно) если такого архива нет, то ближайший к нему с обеих сторон.

    3. сейчас есть архивы в этой папке аж за 2012 год.

    вот как бы мне их разформировать согласно задаче, можно даже создавать папки скажем с именем месяца и туда складывать именно 1 архив. вот не знаю

    Пробовал сдешнюю разработку с распознаванием дат, у меня почемуто сам скрипт пытаеться удалить все файлы старше 1 дня хотя дата их изменения явно совпадает с последним днем прошлого месяца. в чем может быть загвоздка помогите. спасибо за ранее.

    # последняя дата прошлого месяца 
    #$PrevMonth = (Get-Date -Year (Get-Date).year -Month (Get-Date).month -Day 1).adddays(-1)
    #
    # последняя дата 2 месяца назад 
    #$2PrevMonth = (Get-Date -Year $PrevMonth.year -Month $PrevMonth.month -Day 1).adddays(-1)
    #$date = (Get-Date)  - $PrevMonth

    #dir $dist | where {$_.lastwritetime -le (Get-Date).AddDays(-1) -and ($_.lastwritetime -ne (Get-Date).AddDays(-$PrevMonth.Days)) -and ($_.lastwritetime -ne (Get-Date).AddDays(-$2PrevMonth.Days))} #| del -force

    Сейчас этот скрипт удаляет все что было ранее вчерашнего дня.

    16 апреля 2014 г. 11:21
  • Будет удалять файлы, кроме файлов в текущем месяце и самого раннего файла за предыдущий.
    $fdate = (Get-Date -Day 1).Date
    $lldate = $fdate.AddMonths(-1)
    
    $files = Get-ChildItem C:\temp | Where {!$_.PsIsContainer}
    
    $files | Where {$_.LastWriteTime -ge $lldate -and $_.LastWriteTime -lt $fdate} | 
    		Sort LastWriteTime | Select -Skip 1 | Remove-Item -Force -Recurse
    $files | Where {$_.LastWriteTime -lt $lldate} | Remove-Item -Force -Recurse
    

    16 апреля 2014 г. 11:56
    Отвечающий
  • Спасибо, но к моему сожалению этого не хватает, для выполнения поставленной задачи.

    Спасибо огромное за решение части проблемы.

    Пример дело в том что может возникнуть такая ситуация, что скажем самый ранний архив сделался 15 числом, а в предыдущем месяце последний сделан 30 числом или 31 числом, если брать архивы согласно скрипту мы удалим файлы без проверки на давность в итоге получим давность архива в более чем 15 дней.а то и того больше. можно как то устроить проверку какой архив ближе и вот его уже сохранить.

    16 апреля 2014 г. 12:13
  • $fdate = (Get-Date -Day 1).Date
    $lldate = $fdate.AddMonths(-1)
    
    $files = Get-ChildItem C:\temp | Where {!$_.PsIsContainer}
    
    $rem  = $files | Where {$_.LastWriteTime -ge $lldate -and $_.LastWriteTime -lt $fdate} | Sort LastWriteTime
    if($rem[0].LastWriteTime.Date -eq $lldate) {
    	$rem[1..($rem.count-1)] | Remove-Item -Force -Recurse
    }
    else {
    	$rem[0..($rem.count-2)] | Select -Skip 1 
    }
    
    $files | Where {$_.LastWriteTime -lt $lldate} | Remove-Item -Force -Recurse
    

    16 апреля 2014 г. 12:40
    Отвечающий
  • Спасибо еще раз вам, но скрипт не очень корректно работает, видимо причина в том, что в этой папке много архивов и они все с разными именами, и от разных соответсвенно баз.

    А скрипт берег первый к дате и удаляет его... ((

    И подскажите как сделать так, чтобы данный скрипт работал не только на 1 месяц?

    Спасибо

    16 апреля 2014 г. 12:53
  • Спасибо еще раз вам, но скрипт не очень корректно работает, видимо причина в том, что в этой папке много архивов и они все с разными именами, и от разных соответсвенно баз.

    А скрипт берег первый к дате и удаляет его... ((

    И подскажите как сделать так, чтобы данный скрипт работал не только на 1 месяц?

    Спасибо

    Пока очень все расплывчато и непонятно.

    А скрипт берег первый к дате и удаляет его... (( - Сами понимаете?


    • Изменено KazunEditor 16 апреля 2014 г. 13:03
    16 апреля 2014 г. 13:03
    Отвечающий
  • Еще раз описываю ситуацию.

    есть папка C:\Temp

    В ней есть архивы

    1.rar дата последнего изменения 31.03.2014 (архив от базы 1)

    2.rar дата последнего изменения 31.03.2014  (архив от базы 2)

    Backup.rar дата последнего изменения 31.02.2014 (архив от базы Backup)

    В случае когда архив на первой число месяца отсутствует, а архив на 31 актуален, то сохраняется только архив ближайший к дате, В моем случае был 2.rar, остальные удаляются, хотя на самом деле эти архивы, архивы других баз и их также надо сохранять.

    16 апреля 2014 г. 13:09
  • #Получаем все файлы из папки C:\temp

    $files = Get-ChildItem C:\temp | Where {!$_.PsIsContainer}

    # Получаем все файлы за прошлый месяц и сортируем от ранней дате

    $rem  = $files | Where {$_.LastWriteTime -ge $lldate -and $_.LastWriteTime -lt $fdate} | Sort LastWriteTime

    # Проверяем есть ли в прошлом месяце файл за 1 число

    if($rem[0].LastWriteTime.Date -eq $lldate) {

    # Удаляем файлы за прошлый месяц, пропуская 1 число

    $rem[1..($rem.count-1)] | Remove-Item -Force -Recurse

    # Если файла за первое число нет, то берем старший по дате файл. Поправил, в скрипте выше не то добавил

    else {
     $rem[0..($rem.count-2)] | Remove-Item -Force -Recurse
    }

    # Удаляем все файлы младше 1 числа прошлого месяца

    $files | Where {$_.LastWriteTime -lt $lldate} | Remove-Item -Force -Recurse

    16 апреля 2014 г. 13:33
    Отвечающий
  • наверное вот так имелось ввиду?

    $path = "C:\temp"

    #Получаем все файлы из папки C:\temp

    $files = Get-ChildItem $path | Where {!$_.PsIsContainer}

    # Получаем все файлы за прошлый месяц и сортируем от ранней дате

    $rem  = $files | Where {$_.LastWriteTime -ge $lldate -and $_.LastWriteTime -lt $fdate} | Sort LastWriteTime

    # Проверяем есть ли в прошлом месяце файл за 1 число

    if($rem[0].LastWriteTime.Date -eq $lldate) {

    # Удаляем файлы за прошлый месяц, пропуская 1 число

    $rem[1..($rem.count-1)] #| Remove-Item -Force -Recurse

    } #тут не была закрыта процедура если не тут закрыл поправь меня, у меня скрипт не работал.


    # Если файла за первое число нет, то берем старший по дате файл. Поправил, в скрипте выше не то добавил

    else {
     $rem[0..($rem.count-2)] #| Remove-Item -Force -Recurse
    }

    # Удаляем все файлы младше 1 числа прошлого месяца

    $files | Where {$_.LastWriteTime -lt $lldate} #| Remove-Item -Force -Recurse

    Проверил работу скрипта не корректно почему то выкладываю лог удаленных архивов

    -a---        01.03.2014      4:26    1959923 StroyOtdel_db_201403010426.rar   "Remove File" on Target 

    -a---        01.03.2014      3:41    1959923 Doverennost_db_201403010341.rar, а данный файл сохранился.

    Должны были оба сохраниться потому как сами базы разные.

    16 апреля 2014 г. 13:55
  • $fdate = (Get-Date -Day 1).Date
    $lldate = $fdate.AddMonths(-1)
    
    $files = Get-ChildItem C:\temp | Where {!$_.PsIsContainer}
    
    $gr = $files | Group {$_.BaseName.split("_")[0]}
    
    $gr | Foreach {
    	$rem  = $_.Group  | Where {$_.LastWriteTime -ge $lldate -and $_.LastWriteTime -lt $fdate} | Sort LastWriteTime
    	if($rem[0].LastWriteTime.Date -eq $lldate) {
    		$rem[1..($rem.count-1)] | Remove-Item -Force -Recurse
    	}
    	else {
    		$rem[0..($rem.count-2)] | Remove-Item -Force -Recurse
    	}
    	$_.Group| Where {$_.LastWriteTime -lt $lldate} | Remove-Item -Force -Recurse
    }	

    16 апреля 2014 г. 14:07
    Отвечающий
  • при выполнения скрипта валяться ошибки такого характера (((.

    Cannot index into a null array.
    At C:\Test_script\Test1.ps1:12 char:10
    +     if($rem[ <<<< 0].LastWriteTime.Date -eq $lldate) {
        + CategoryInfo          : InvalidOperation: (0:Int32) [], RuntimeException
        + FullyQualifiedErrorId : NullArray

    17 апреля 2014 г. 4:29
  • $fdate = (Get-Date -Day 1).Date $lldate = $fdate.AddMonths(-1) $files = Get-ChildItem C:\temp | Where {!$_.PsIsContainer} $gr = $files | Group {$_.BaseName.split("_")[0]} $gr | Foreach { $rem = $_.Group | Where {$_.LastWriteTime -ge $lldate -and $_.LastWriteTime -lt $fdate} | Sort LastWriteTime if($rem[0].LastWriteTime.Date -eq $lldate) { $rem[1..($rem.count-1)] | Remove-Item -Force -Recurse } else { $rem[0..($rem.count-2)] | Remove-Item -Force -Recurse } $_.Group| Where {$_.LastWriteTime -lt $lldate} | Remove-Item -Force -Recurse }

    Это скрипт работает единственное, что падают ошибки...

    и этот скрипт работает только с давностью 1 месяц, можно как то его расширить скажем на год?

    Что именно я имею ввиду:

    Скрипт проверяет текущий месяц, не делает ничего с архивами. Оставляет их как и должно быть.

    Далее он группирует файлы взятые за предыдущий месяц по имени, проверяет наличия архива на 1 число.

    Если такой есть, архив остается, остальные удаляются, если архива нет берется ближайший к нему. ТО что надо.

    А вот далее скрипт работает простым удаление все что было создано(WriteTime.Date) раньше прошлого месяца в частности (01.03.214)

    Просто удаляются без повторной процедуры.

    Можно ли сделать данный скрипт чтобы он работал на передушившие 12 месяцев?

    ТО есть как я это вижу. Сперва определяется текущий месяц.

    Далее происходит процесс группировке не только по имени но и по месяцу,

    а вот уже в группе месяца производиться проверка на наличие архива на 1 число,

    если такого нет, то ближайший к нему с обеих сторон,

    то есть если архивы есть от 15.03.2014 и 28.02.2014, то остаться должен за 28 число.

    и так скажем давность 12 месяцев.

    За ранее спасибо.

    17 апреля 2014 г. 4:51
  • Еще выявил одну вещь.

    отсутствие архива на 1 число.

    архив ближайший к нему сохраняется, НО

    за первое число и ближайший к нему удаляются.

    Пример.

    есть архивы. 

    Volosovo_IP_db_201403310316.rar Дата изменения: 31.03.2014

    Volosovo_IP_db_201404030202.rar Дата изменения: 03.04.2014

    Volosovo_IP_db_201403050536.rar Дата изменения: 05.03.2014

    Volosovo_IP_db_201402280517.rar Дата изменения: 28.02.2014

    После выполнения скрипта: остаются только архивы

    Volosovo_IP_db_201403310316.rar Дата изменения: 31.03.2014

    Volosovo_IP_db_201404030202.rar Дата изменения: 03.04.2014

    Два других удаляются, но по сути должен был остаться,

    Volosovo_IP_db_201402280517.rar Дата изменения: 28.02.2014

    а если его бы не было тогда. 

    Volosovo_IP_db_201403050536.rar Дата изменения: 05.03.2014

    то этот.

    17 апреля 2014 г. 5:16
  • # Текущий месяц
    $fdate = (Get-Date -Day 1).Date
    # Из $fdate вычитаем 12 месяцев
    $lltw = $fdate.AddMonths(-12)
    
    # Получаем файлы,которые созданы в интервале $lltw и $fdate, и удаляем те что старше
    $files = Get-ChildItem C:\temp | Where {!$_.PsIsContainer -and $_.LastWriteTime -lt $fdate} | Foreach {
    	if($_.LastWriteTime -lt $lltw) {
    		Remove-Item $_.FullName -Force -Recurse
    	}
    	else {
    		$_
    	}
    }
    
    # Группируем по названию базы
    $gr = $files | Group {$_.BaseName.split("_")[0]}
    
    $gr | Foreach {
    	# Группируем по месяцам, если в месяце 1 архив, то пропускаем. Далее ищем за 1-ое число, если нет, то берем 
    	# старший файл
    	$_.Group | Group {$_.LastWriteTime.Date.ToString("MMyyyy")} | Where {$_.Count -gt 1} | Foreach {
    		$rem  = $_.Group | Sort LastWriteTime
    		if($rem[0].LastWriteTime.Date.ToString("dd") -eq "01") {
    			$rem | Where {$_.LastWriteTime.Date.ToString("dd") -ne "01"} | Remove-Item -Force -Recurse
    		}
    		else {
    			$rem | Sort -Descending | Select -Skip 1 | Remove-Item -Force -Recurse
    		}
    	}
    }	

    • Помечено в качестве ответа HeartlesSpb 17 апреля 2014 г. 5:44
    17 апреля 2014 г. 5:33
    Отвечающий
  • Супер то, что надо.

    а как в него добавить лог отказа? в случае если что то пошло не так, скажем не дошол до полного завершения.

    17 апреля 2014 г. 5:44
  • Самое просто добавить в начало скрипта:

    Start-Transcript -Path log.txt

    В конец:

    Stop-Transcript

    17 апреля 2014 г. 5:50
    Отвечающий
  • Спасибо.

    Столкнулся вот еще с чем. Перед удалением решил просто переместить фалы в другую папку чтобы не удалить сразу все. (побаиваюсь что, что то не так будет).

    Вместо

    Remove-Item $_.FullName -Force -Recurse

    ставлю.

    Move-Item $_.FullName $dest -Force (Где $dest = "c:\temparyfile)

    Заменил все три. почему то не работает, подскажи что не так?

    17 апреля 2014 г. 6:01
  • Где:

    Remove-Item $_.FullName -Force -Recurse

    Заменить на:

    Move-Item $_.FullName -Destination $dest

    Где:

    Remove-Item -Force -Recurse

    Заменить на:

    Move-Item -Destination $dest

    • Помечено в качестве ответа HeartlesSpb 17 апреля 2014 г. 6:29
    17 апреля 2014 г. 6:21
    Отвечающий
  • Прости сам тормоз сразу не заметил.

    спасибо еще раз.

    17 апреля 2014 г. 6:29
  • Снова я, протестировал на своей уже рабочей папке выяснил что не так работает.

    есть архивы в папке. c:\temp

    Volosovo_IP_db_201402280517 дата 28.02.2014 5:17

    Volosovo_IP_db_201403010534 дата 01.03.2014 5:34

    Volosovo_IP_db_201403030605 дата 03.03.2014 6:05

    Volosovo_IP_db_201403040536 дата 04.04.2014 5:36

    Volosovo_IP_db_201403310316 дата 31.03.2014 3:16

    При первом запуске отработало все ок остался только:

    Volosovo_IP_db_201403010534 дата 01.03.2014 5:34

    Но я пошел дальше и смоделировал когда у меня на первое число нет архива:

    Volosovo_IP_db_201402280517 дата 28.02.2014 5:17

     

    Volosovo_IP_db_201403030605 дата 03.03.2014 6:05

    Volosovo_IP_db_201403040536 дата 04.04.2014 5:36

    Volosovo_IP_db_201403310316 дата 31.03.2014 3:16

    Получил сохраненный файл:

    Volosovo_IP_db_201403310316 дата 31.03.2014 3:16

    Это не правильно разрыв получается в 2 месяца с предыдущим архивом. 

    Должен был остаться ближайший к 1 числу.

    ТО есть: 

    Volosovo_IP_db_201402280517 дата 28.02.2014 5:17

    17 апреля 2014 г. 6:56
  • 1) Как оно могло отработать при первом запуске правильно, если даты разные? Должно остаться:

    Volosovo_IP_db_201402280517 дата 28.02.2014 5:17

    Volosovo_IP_db_201403010534 дата 01.03.2014 5:34

    2) Опять же месяцы разные, 2 и 3, должно остаться

    Volosovo_IP_db_201402280517 дата 28.02.2014 5:17

    Volosovo_IP_db_201403010534 дата 01.03.2014 5:34

    Это не правильно разрыв получается в 2 месяца с предыдущим архивом. - Это с каким? 28.02 и 31.03 разница в месяц. Если отчет вести с 1.02 и в феврале 1 архив, то он остается.

    17 апреля 2014 г. 7:12
    Отвечающий
  • Поправил правила сортировки стало лучше но еще не идеально.

    С этого

    $rem | Sort -Descending | Select -Skip 1 | Remove-Item -Force -Recurse

    На Это

    $rem | Sort | Select -Skip 1 | Remove-Item -Force -Recurse

    Теперь остается архив:

    Volosovo_IP_db_201403030605 дата 03.03.2014 6:05

    Это намного лучше но хочется чтобы все таки ближайший к 1 числу сохранялся.

    17 апреля 2014 г. 7:14
  • 1) Как оно могло отработать при первом запуске правильно, если даты разные? Должно остаться:

    Volosovo_IP_db_201402280517 дата 28.02.2014 5:17

    Volosovo_IP_db_201403010534 дата 01.03.2014 5:34

    2) Опять же месяцы разные, 2 и 3, должно остаться

    Volosovo_IP_db_201402280517 дата 28.02.2014 5:17

    Volosovo_IP_db_201403010534 дата 01.03.2014 5:34

    Это не правильно разрыв получается в 2 месяца с предыдущим архивом. - Это с каким? 28.02 и 31.03 разница в месяц. Если отчет вести с 1.02 и в феврале 1 архив, то он остается.

    1. После отработки скрипта копировал все обратно чтобы проверить что будет если отсутствует файл на первое число. Ты прав если в месяце есть только 1 архив он и правда остается.Но у нас за месяц 02 несколько архивов и есть архив на первое число 01.02.2014, он как раз остается.

    НО если архива нет на 1 число следующего месяца то есть нут файла на 01.03.2014 то оставался архив на 31.03.2014, что по всему списку остававшихся архивов получается.

    Архив за 01.02.2014

    Архив за 31.03.2014

    Разрыв более месяца. 

    Ниже поправил сортировку.картина стала лучше.

    архивы есть за 01.02.2014

    архивы есть за 03.03.2014

    Идеальная картина.

    архив от 01.02.2014

    архив от 28.02.2014 (он ближе чем 03.03.2014 к первому числу месяца)

    архив от 01.04.2014

    17 апреля 2014 г. 7:25
  • Оставить два файла в месяце первый и последний, и не надо выдумывать.
    17 апреля 2014 г. 7:38
    Отвечающий
  • Как вариант.

    Но к сожалению не я такое выдумываю. Есть другие люди которые любят фантазировать.

    Но вот только я сейчас  как раз над этим думаю и не могу понять куда что поставить :(.

    желпанешь?

    17 апреля 2014 г. 7:42
  • Чтобы оставить первый и последний файл в месяце:

    $rem  = $_.Group | Sort LastWriteTime
    		if($rem[0].LastWriteTime.Date.ToString("dd") -eq "01") {
    			$rem | Where {$_.LastWriteTime.Date.ToString("dd") -ne "01"} | Remove-Item -Force -Recurse
    		}
    		else {
    			$rem | Sort LastWriteTime -Descending | Select -Skip 1 | Remove-Item -Force -Recurse
    		}

    Заменить на:

    $rem  = $_.Group | Sort LastWriteTime
    $notdelete = $rem | Select -First 1 -Last 1 | Foreach {$_.Name}
    $rem | Where {$notdelete -notcontains $_.Name} | Remove-Item -Force -Recurse



    • Изменено KazunEditor 17 апреля 2014 г. 8:08
    17 апреля 2014 г. 7:58
    Отвечающий
  • Еще раз подумал и пришел к выводу что надо делать как стоит задача иначе просто не умещусь в объем HDD архивы по пол терабайта. Может сделать двумя скриптами? скажем в одном будет как раз сохранять первый и последний архив за месяц, а вторым проверять наличие на 1 число архива если такой есть, удалять последний архив из предыдущего месяца, а если такого нет проверить какой более удален по дате от 1 числа тот удалить второй оставить.
    17 апреля 2014 г. 8:33
  • 1) на 1 число архива если такой есть, удалять последний архив из предыдущего месяца

    1.01 - 1   29.02 - 2 1.03 -3 3.04 -4    - По логике в 1.03 грохнет 29.02 и образуется промежуток 1.01 и 1.03

    2) а если такого нет проверить какой более удален по дате от 1 числа тот удалить второй оставить.

    1.01 -1 30.01 -2 2.02 - 3 29.02 -3 2.03 -4 - По логике 2.02  ближе к 1.02 и 29.02 может ближе к 1.03, чем 2.03.

    17 апреля 2014 г. 9:03
    Отвечающий
  • 1) на 1 число архива если такой есть, удалять последний архив из предыдущего месяца

    1.01 - 1   29.02 - 2 1.03 -3 3.04 -4    - По логике в 1.03 грохнет 29.02 и образуется промежуток 1.01 и 1.03

    2) а если такого нет проверить какой более удален по дате от 1 числа тот удалить второй оставить.

    1.01 -1 30.01 -2 2.02 - 3 29.02 -3 2.03 -4 - По логике 2.02  ближе к 1.02 и 29.02 может ближе к 1.03, чем 2.03.

    1. Конечно немного не так. В таком случае как у вас описан должны быть все 4 архива, причина отсутствие других архивов за 1,2,3,4 месяцы. (ТО есть за месяц должен быть всегда 1 архив), и если вернутся  все таки к основной задаче то должен быть архив ближайший к 1 числу месяца в обе стороны. то есть 29.02 должен остаться потому как на первое число месяца 2 не было архива, а архив от 29,02 ближайший к 1 числу месяца.

    2. смотрим на 1 число 2 месяца нет архива, проверяем какой ближе к 1.02 архив. то есть надо сравнить LastWriteTime.HHmm 30.01 и 2.02, выясним какой из них ближе. тот и оставим, соответственно с 29.02 и 2.03 то же самое. 

    17 апреля 2014 г. 9:45
  • как вариант может попробовать через DayofYear.

    то есть получить первое число месяца, параметр DayOfYear.

    допустим что это будет 01.04 у него DayOfYear 100.

    у предыдущего архива дата 31.03 DayOfYear 99.

    и у третьго который надо сравнить 05.04 DayOfYear 105.

    соответвенно делаем арифметику типа

    (100 - 99) и (100-105(-1))

    выявляем что меньше его и оставляем.

    так можно сделать?

    17 апреля 2014 г. 11:25
  • #рабочий каталог

    $path = "c:\temp"

    $dest = "c:\temp1"

    # Текущий месяц
    $fdate = (Get-Date -Day 1).Date
    # Из $fdate вычитаем 12 месяцев
    $lltw = $fdate.AddMonths(-12)

    # Получаем файлы,которые созданы в интервале $lltw и $fdate, и удаляем те что старше
    $files = Get-ChildItem $path | Where {!$_.PsIsContainer -and $_.LastWriteTime -lt $fdate} | Foreach {
    if($_.LastWriteTime -lt $lltw) {
    Move-Item $_.FullName -Destination $dest
    }
    else {
    $_
    }

    }

    # Группируем по названию базы
    $gr = $files | Group {$_.BaseName.split("_")[0]}

    $gr | Foreach {
    # Группируем по месяцам, если в месяце 1 архив, то пропускаем. Далее ищем за 1-ое число, если нет, то берем 
    # старший файл
    $_.Group | Group {$_.LastWriteTime.Date.ToString("yyyyMMdd")} | Where {$_.Count -gt 1} | Foreach {
    $rem  = $_.Group | Sort LastWriteTime 

    if($rem[0].LastWriteTime.Date.ToString("dd") -eq "01") {
    $rem | Where {$_.LastWriteTime.Date.ToString("dd") -ne "01"} | Move-Item -Destination $dest
    }

    Вот до этого момента все ок, а вот теперь осталось дописать что делать если на первое число файла нет, надо как то отсортировать первый в текущем месяце и последней в предыдущем.

    и методом простого вычитание дат от первого числа месяца сравнить если больше то один файл если меньше то другой.

    Пример

    Else ("файл прошлого месяца".LastWriteTime.Date.ToString(yyyyMMdd) - "01 число текущего месяца") -lt ("файл прошлого месяца".LastWriteTime.Date.ToString(yyyyMMdd)  - "01 число текущего месяца" )

    | move-item "файл прошлого месяца".LastWriteTime.Date.ToString(yyyyMMdd) -Destination $dest

    17 апреля 2014 г. 12:59
  • тфу сортировка не правильная.

    LastWriteTime.Date.ToString("yyyyMMdd")

    должна быть

    LastWriteTime.Date.ToString("ddMMyyyy")

    17 апреля 2014 г. 13:05
  • Немного подумав пришел к следующему.

    cls
    $path = "C:\temp\1"
    $dest = "C:\temp\2"
    # Текущий месяц
    $fdate = (Get-Date -Day 1).Date
    # Из $fdate вычитаем 12 месяцев
    $lltw = $fdate.AddMonths(-12)

    # Получаем файлы,которые созданы в интервале $lltw и $fdate, и удаляем те что старше
    $files = Get-ChildItem $path | Where {!$_.PsIsContainer -and $_.LastWriteTime -lt $fdate} | Foreach {
    if($_.LastWriteTime -lt $lltw) {
    Move-Item $_.FullName -Destination $dest
    }
    else {
    $_
    }
    }

    # Группируем по названию базы
    $gr = $files | Group {$_.BaseName.split("_")[0]}
    $gr2 = $files | Group {$_.BaseName.split("_")[0]}
    $gr | Foreach {
    # Группируем по месяцам, Оставляем первый и последний архив 

    $_.Group | Group {$_.LastWriteTime.Date.ToString("MMyyyy")} | Where {$_.Count -gt 1} | Foreach {
    $rem  = $_.Group | Sort LastWriteTime
    $notdelete = $rem | Select -First 1 -Last 1 | Foreach {$_.Name}
    $rem | Where {$notdelete -notcontains $_.Name} | Move-Item -Destination $dest
    }
    }
    $gr2 | Foreach {
    # Группируем по месяцам, если в месяце 1 архив, то пропускаем. Далее ищем за 1-ое число, если нет, то берем 
    # старший файл
    $_.Group | Group {$_.LastWriteTime.Date.ToString("MMyyyy")} | Where {$_.Count -gt 1} | Foreach {
    $rem  = $_.Group | Sort LastWriteTime
    if($rem[0].LastWriteTime.Date.ToString("dd") -eq "01") {
    $rem | Where {$_.LastWriteTime.Date.ToString("dd") -ne "01"} | Move-Item -Destination $dest
    }
    else {
    $rem | Sort -Descending

    #| Select -Skip 1 | Write-Host "Error"
    }
    }
    }

    Таким образом получил группу файлов которые надо сравнить, причем группа как раз из 2-х файлов.

    до и после 1 числа, если кто поможет будет супер. но хочется новую тему открывать

    17 апреля 2014 г. 13:40
  • cls
    #Задаем переменные путей 1 путь где хпраняться архивы
    #2 место откуда в последсвие будем удалять все ненужное
    $path = "C:\Test_script\1"
    #папка сохранёных архивов, туда будут перемещаться архивы которые не попадают в переуд сравнения
    $d = "C:\Test_script\2"
    # Задаем переменные дат. 
    # 30 дней назад от текущей даты.
    $Rdate = (Get-Date).adddays(-30)
    # Получаем список файлов старше 30 дней
    $files = Get-ChildItem $path | Where {!$_.PsIsContainer -and $_.LastWriteTime -lt $rdate} 
    # Группируем по названию базы
    # Группируем файлы в массиве по имени убирая все что правее 4 в имени.
    $gr = $files | Group {$_.BaseName.split("4")[0]}
    # после групировке запуская пофайловую проверку.
    $gr | Foreach {
        # в группе проверяем удаленность от 1 числа прошлого месяца, пропускаем 1 попавшийся остальные удаляем
        $_.Group |%{Add-Member -type NoteProperty -InputObject $_ -name Seconds -value $([math]::abs((([datetime]$_.lastwritetime) - ((get-date -day 1).AddMonths(-1).date)).TotalSeconds)) -force}
                        $_.group|sort -Property Seconds|select -Skip 1 | move-item -Destination $d 
                }

    С уважением HeartlesSpb.

    • Помечено в качестве ответа HeartlesSpb 21 мая 2014 г. 9:28