none
Помощь в оптимизации скрипта PowerShell RRS feed

  • Вопрос

  • Гуру Powershell'a, нужна Ваша помощь.

    Стояла простенькая задача - в неком каталоге лежать файлы(логи), необходимо было их отсортировать по дате создания и разложить по папкам типа \год\месяц\, и в дальнейшем чтобы скрипт скажем раз в месяц выполнялся и накопившиеся файлы снова отсортировал, а также вел простой лог в текстовом файле. Я сделал так, все работает, все хорошо, но я неопытный боец в этом деле и мне кажется что я перемудрил,


    #=================================Переменные===================================================
    #Путь, где находятся файлы требующие сортировки
    $path = "G:\work\"

    #================================Функции=======================================================
    #Функция ведения лога скрипта
    Function Log($message){
    Add-Content -Path "c:\log.txt" -Value ((Get-Date -Format "g") + "   " + $message)
    }
    #Функция проверки на ошибки выполнения команд и запись результата в лог файл
    Function Check-Error($err){
    if($err.count -eq 0){
    Log("OK")
    }
    else{Log("Ошибка ::" + $err)
    }
    Remove-Item variable:err
    }
    #================================Тело скрипта==================================================
    #Получаем список логфайлов в заданной директории
    Log("="*70)
    Log("Получаем список файлов для сортировки...")
    $Log_files = Get-ChildItem $path -ErrorVariable err | where{$_.name -match "novoplat" -and $_.psiscontainer -eq $false} 
    Check-Error($err)

    #Анализируем файлы по дате создания(год), и все уникальные даты передаем в массив 
    Log("Анализ дат создания файлов...")
    $Log_files | ForEach-Object -Begin {$arr = @()} -Process {$arr += $_.LastWriteTime.year} -End {$arr_temp = $arr | select -Unique} -ErrorVariable err
    Check-Error($err)

    #Удаляем временный массив $arr
    Remove-Item variable:arr

    #Создаем папки с наименованием года, наименование извлекаем из массива и в каждой создаем еще 12(месяцы)
    Log("Создаем папки...")
    foreach ($a in $arr_temp) {
    #Проверяем существует ли уже директория
    if((Test-Path ($path + $a)) -eq $false){
    Log("Создаю папку " + $path + $a + "...")
    New-Item -ItemType directory ($path + $a) -ErrorVariable err
    Check-Error($err)
    for ($i = 1; $i -le 12; $i++){
    if($i -lt 10){
    New-Item -ItemType directory ($path + $a + "\" + "0" + $i)
    }
    else{
    New-Item -ItemType directory ($path + $a + "\" + $i)
    }
    }
    }else{Log("Диретория " +$path + $a + " существует")

    Check-Error($err)

    #Сортируем файлы по папкам
    Log("Сортируем файлы по папкам...")
    foreach($f in $Log_files){
    Move-Item $f.FullName -Force -Destination ($path + $f.LastWriteTime.ToString("d").Substring(6,4) + "\" + $f.LastWriteTime.ToString("d").Substring(3,2)) -ErrorVariable err
    }
    Check-Error($err)

    Если несложно, поправьте меня или быть может Ваши варианты решения этой задачи. Я уверен что код может быть меньше и проще, но не знаю как это сделать.

Ответы

  • $Path = "C:\Test"
    Get-ChildItem $Path -Recurse | ? {!$_.PSIsContainer} | Move-Item -Destination {
    	md "$path\$($_.LastWriteTime.ToString("yyyy\\MM"))" -Force
    }

    • Помечено в качестве ответа SteFFun 4 июня 2012 г. 7:18
    Отвечающий
  • for($i=2012; $i -le 2020; $i++){ #создаём папки для годов 2012-2020. меняем диапазон по желанию :)
    	New-Item -ItemType directory -Path $path -Name $i -ErrorVariable err
    	for($j=1; $j -le 12; $j++) {
    		New-Item -ItemType directory -Path "$path\$i" -Name $j -ErrorVariable err
    	}
    }
    $path = 'C:\temp\123'
    Get-ChildItem $path | where {!$_.PSIsContainer}| %{ #перемещаем
    	$year = $_.LastWriteTime.year
    	$month = $_.LastWriteTime.month
    	Move-Item $_.fullname  -Destination "$path\$year\$month" -Force
    }

    Я бы сделал вот так. :) Первую часть с созданием папок делать один раз, вторую часть с перемещением запускать по мере надобности.

    З.Ы. если надо лог, то добавить в цикл переноса строчку типа

    add-Content -Path c:\Log\log.txt -Value ($_.fullname + '; ' + "$path\$year\$month")

    • Изменено Deft_ 31 мая 2012 г. 9:37
    • Помечено в качестве ответа SteFFun 31 мая 2012 г. 9:48
  • Чё-то вы как-то действительно извратились со скриптом :)

    $Path = "G:\Works"
    $Logs = Get-ChildItem $Path -Recurse | ? {!$_.PSIsContainer}
    foreach ($Log in $Logs) {
        $Month = "0"+$Log.LastWriteTime.Month
        $Month = $Month.Substring($Month.Length-2,2)
        $Year = $Log.LastWriteTime.Year
        $Dest = $Path + "\" + $Year
        If (!(Test-Path $Dest)) {
            New-Item -Path $Dest -ItemType Directory -Force}
        $Dest = $Dest + "\" + $Month
        If (!(Test-Path $Dest)) {
            New-Item -Path $Dest -ItemType Directory -Force}
        Move-Item -Path $Log.Fullname -Destination $Dest -Force
    }


    • Изменено Vladimir Zelenov 31 мая 2012 г. 10:16
    • Помечено в качестве ответа SteFFun 4 июня 2012 г. 7:20

Все ответы

  • for($i=2012; $i -le 2020; $i++){ #создаём папки для годов 2012-2020. меняем диапазон по желанию :)
    	New-Item -ItemType directory -Path $path -Name $i -ErrorVariable err
    	for($j=1; $j -le 12; $j++) {
    		New-Item -ItemType directory -Path "$path\$i" -Name $j -ErrorVariable err
    	}
    }
    $path = 'C:\temp\123'
    Get-ChildItem $path | where {!$_.PSIsContainer}| %{ #перемещаем
    	$year = $_.LastWriteTime.year
    	$month = $_.LastWriteTime.month
    	Move-Item $_.fullname  -Destination "$path\$year\$month" -Force
    }

    Я бы сделал вот так. :) Первую часть с созданием папок делать один раз, вторую часть с перемещением запускать по мере надобности.

    З.Ы. если надо лог, то добавить в цикл переноса строчку типа

    add-Content -Path c:\Log\log.txt -Value ($_.fullname + '; ' + "$path\$year\$month")

    • Изменено Deft_ 31 мая 2012 г. 9:37
    • Помечено в качестве ответа SteFFun 31 мая 2012 г. 9:48
  • Спасибо за идею, это поможет мне упростить скрипт. 
  • Пожалуйста. :)
  • Чё-то вы как-то действительно извратились со скриптом :)

    $Path = "G:\Works"
    $Logs = Get-ChildItem $Path -Recurse | ? {!$_.PSIsContainer}
    foreach ($Log in $Logs) {
        $Month = "0"+$Log.LastWriteTime.Month
        $Month = $Month.Substring($Month.Length-2,2)
        $Year = $Log.LastWriteTime.Year
        $Dest = $Path + "\" + $Year
        If (!(Test-Path $Dest)) {
            New-Item -Path $Dest -ItemType Directory -Force}
        $Dest = $Dest + "\" + $Month
        If (!(Test-Path $Dest)) {
            New-Item -Path $Dest -ItemType Directory -Force}
        Move-Item -Path $Log.Fullname -Destination $Dest -Force
    }


    • Изменено Vladimir Zelenov 31 мая 2012 г. 10:16
    • Помечено в качестве ответа SteFFun 4 июня 2012 г. 7:20
  • $Path = "C:\Test"
    Get-ChildItem $Path -Recurse | ? {!$_.PSIsContainer} | Move-Item -Destination {
    	md "$path\$($_.LastWriteTime.ToString("yyyy\\MM"))" -Force
    }

    • Помечено в качестве ответа SteFFun 4 июня 2012 г. 7:18
    Отвечающий
  • Подскажите, пожалуйста, что значит "md"?

    -Destination { md ...

    В описании командлета move и параметра -Destination ничего такого не нашёл. Подозреваю что это связано с созданием каталогов, но что конкретно делает?

    Или ссылочку где почитать, если не сложно. :)

    Спасибо.

  • Подскажите, пожалуйста, что значит "md"?

    -Destination { md ...

    В описании командлета move и параметра -Destination ничего такого не нашёл. Подозреваю что это связано с созданием каталогов, но что конкретно делает?

    Или ссылочку где почитать, если не сложно. :)

    Спасибо.

    md является альясом на mkdir,в свою очередь mkdir это Proxy Function на командлет New-Item.
    Отвечающий
  • Вы всегда можете узнать что делает тот или иной командлет с помощью команды Get-Help.

  • Не догадался, что это алиас к командлету :) Спасибо за пояснения, теперь всё осознал.


    • Изменено Deft_ 1 июня 2012 г. 6:46
  • Вот это да! 3 строчки, я знал что все намного проще. Kazun, Вы как всегда на высоте! Огромное спасибо.
  • Перемудрил я, от неопытности. Ваш вариант тоже хорош, все просто и понятно. Спасибо за помощь.