Powershell - последовательный foreach l oop архивирование файлов - PullRequest
1 голос
/ 11 февраля 2020

У меня есть несколько серверов IIS, на каждом из которых есть несколько сайтов, и я хочу регулярно архивировать все журналы IIS.

Я с помощью этого сайта и Google соединил следующий скрипт powershell:

$files = Get-ChildItem  "D:\logfiles\IIS-Logs\*.log" -Recurse | Where-Object {($_.LastWriteTime -lt (Get-Date).AddDays(-7))} 
foreach ($file in $files) {& 'C:\Program Files\WinRAR\winrar.exe' a -tl -df -m5 "$file.rar" $File}

Проблема с этим сценарием в том, что если есть ... скажем ... 2 000 всего журнала файлы, которые он пытался запустить 2000 одновременных копий Winrar и сервер взломает sh. Это было неожиданно. Я ожидал, что это заархивирует файлы по одному за раз. Последовательно.

У кого-нибудь есть идеи сделать эту работу, как я хочу?

Я бы очень хотел использовать Winrar против нативной опции Compress-Archive, потому что:

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

Я не женат на Винраре, если смогу добиться этого другим способом.

Ответы [ 2 ]

1 голос
/ 11 февраля 2020

Для целей тестирования я создал LogFolder с 3 отдельными папками журналов, Log1, Log2 и Log3. Каждая из этих папок журнала имеет 2000 файлов с данными по 2 МБ каждый. Это команда, которую я выполнил для Сжатия каждой папки `отдельно

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


$ElementsInLog = (Get-ChildItem C:\temp\LogFolder\*.txt -Recurse).Length
$ElementsInLog1 = (Get-ChildItem C:\temp\LogFolder\Log1\*.txt -Recurse).Length
$ElementsInLog2 = (Get-ChildItem C:\temp\LogFolder\Log2\*.txt -Recurse).Length
$ElementsInLog3 = (Get-ChildItem C:\temp\LogFolder\Log3\*.txt -Recurse).Length

Write-Output "Main: $ElementsInLog`nLog1: $ElementsInLog1`nLog2: $elementsInLog2`nLog3: $elementsInLog3"
Write-output "Total File Size: $((Get-ChildItem C:\temp\LogFolder\Log1\*.txt -Recurse | Measure-Object length -Sum).Sum / 1024 / 1024 / 1024) GB"


Write-Output "Starting Tasks..."

$job1 = Start-Job -ScriptBlock {
  Write-Output "Log1: $(Get-Date -Format G)"
  Get-ChildItem C:\temp\LogFolder\Log1 -Recurse | Compress-Archive -DestinationPath C:\temp\log1.zip -CompressionLevel Fastest
  Write-Output "Finished: $(Get-Date -Format G)"
}

$job2 = Start-Job -ScriptBlock {
    Write-Output "Log2: $(Get-Date -Format G)"
    Get-ChildItem C:\temp\LogFolder\Log3 -Recurse | Compress-Archive -DestinationPath C:\temp\log3.zip -CompressionLevel Fastest
    Write-Output "Finished: $(Get-Date -Format G)"
}

$job3 = Start-Job -ScriptBlock {
    Write-Output "Log2: $(Get-Date -Format G)"
    Get-ChildItem C:\temp\LogFolder\Log4 | Compress-Archive -DestinationPath C:\temp\log4.zip -CompressionLevel Fastest
    Write-Output "Finished: $(Get-Date -Format G)"
}

while($job1.State -eq "Running" -or $job2.State -eq "Running" -or $job3.State -eq "Running") { 
    Start-Sleep 5
}

Receive-Job $job1
Receive-Job $job2
Receive-Job $job3


Выход получен

Main: 8000
Log1: 2000
Log2: 2000
Log3: 2000
Total File Size: 4.12791967391968 GB

Starting Tasks...
Log1: 2/10/2020 8:36:22 PM
Finished: 2/10/2020 8:37:30 PM
Log2: 2/10/2020 8:36:22 PM
Finished: 2/10/2020 8:37:27 PM
Log3: 2/10/2020 8:36:22 PM
Finished: 2/10/2020 8:37:28 PM
0 голосов
/ 11 февраля 2020

Вы, вероятно, хотите использовать "Start-Process -Wait" вместо использования &. Использование флага -Wait в Start-Process заставляет его ждать завершения, а затем запускает вашу программу последовательно. Прочтите эту статью о том, как использовать Start-Process: лучший процесс запуска PowerShell. Вы также можете использовать командлет Compress-Archive вместо программы командной строки Winrar, которая может быть лучше интегрирована и даст вам более эффективную обратную связь в ваших сценариях.

Как-то так с WinRAR?

$files = Get-ChildItem  "D:\logfiles\IIS-Logs\*.log" -Recurse | Where-Object {($_.LastWriteTime -lt (Get-Date).AddDays(-7))}
foreach ($file in $files) {
    $args = 'a -tl -df -m5 "' + $file.rar + '" ' + $File
    Start-Process -Wait -filepath 'C:\Program Files\WinRAR\winrar.exe' -ArgumentList $args
}

Или это с Compress-Archive

$files = Get-ChildItem  "D:\logfiles\IIS-Logs\*.log" -Recurse | Where-Object {($_.LastWriteTime -lt (Get-Date).AddDays(-7))}
foreach ($file in $files) {
    Compress-Archive -Path $file.FullName -DestinationPath "$($File.FullName).rar"
{

Выше не протестировано, но должно работать, если я не сделал опечатку.

...