Объедините несколько файлов журнала в архив с помощью PoSh и 7zip - PullRequest
0 голосов
/ 06 ноября 2018

Я пытаюсь объединить несколько файлов журнала в один файл архива, а затем переместить этот файл архива в другое место, чтобы очистить старые файлы журнала и сэкономить место на жестком диске. У нас есть куча инструментов, которые все входят в один и тот же корень, с папкой для каждого журнала. (Например,

  1. C: \ ServerLogs
  2. C: \ ServerLogs \ App1
  3. C: \ ServerLogs \ 2ndApp

каждый из которых будет иметь файлы журнала внутри, как

  1. C: \ ServerLogs \ App1 \ June1.log
  2. C: \ ServerLogs \ App1 \ June2.log
  3. C: \ ServerLogs \ 2ndApp \ June1.log
  4. C: \ ServerLogs \ 2ndApp \ June2.log

Я хочу зайти в каждую из этих подпапок, заархивировать все файлы старше 5 дней, затем переместить архив на другой диск (долговременное хранилище) и удалить архивированные файлы. Я использую инструменты PowerShell и 7zip. В приведенном ниже коде используются места тестирования.

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

# Alias for 7-zip 
if (-not (test-path "$env:ProgramFiles\7-Zip\7z.exe")) {throw "$env:ProgramFiles\7-Zip\7z.exe needed"} 
set-alias 7zip "$env:ProgramFiles\7-Zip\7z.exe" 
$Days = 5 #minimum age of files to archive; in other words, newer than this many days ago are ignored
$SourcePath = C:\WorkingFolder\FolderSource\
$DestinationPath = C:\Temp\
$LogsToArchive = Get-ChildItem -Recurse -Path $SourcePath | Where-Object {$_.lastwritetime -le (get-date).addDays(-$Days)}
$archive = $DestinationPath + $now + ".7z"

#endregion

foreach ($log in $LogsToArchive) {
    #define Args
    $Args = a -mx9 $archive $log
    $Command = 7zip
    #write-verbose $command

    #invoke the command
    invoke-expression -command $Command $Args

Проблема с этим в том, что я получаю ошибки, пытаясь вызвать выражение. Я попытался реструктурировать его, но потом я получаю ошибки, потому что мои $ Args имеют «a»

Поэтому я отказался от этого метода (несмотря на то, что он был моим предпочтением) и попробовал этот набор.

#region Params
param(
    [Parameter(Position=0, Mandatory=$true)]
    [ValidateScript({Test-Path -Path $_ -PathType 'container'})]
    [System.String]
    $SourceDirectory,
    [Parameter(Position=1, Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [System.String]
    $DestinationDirectory
)
#endregion

function Compress-File{
    #region Params
    param(
        [Parameter(Position=0, Mandatory=$true)]
        [ValidateScript({Test-Path -Path $_ -PathType 'leaf'})]
        [System.String]
        $InputFile,
        [Parameter(Position=1, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $OutputFile
    )
    #endregion

    try{
        #Creating buffer with size 50MB
        $bytesGZipFileBuffer = New-Object -TypeName byte[](52428800)

        $streamGZipFileInput = New-Object -TypeName System.IO.FileStream($InputFile,[System.IO.FileMode]::Open,[System.IO.FileAccess]::Read)
        $streamGZipFileOutput = New-Object -TypeName System.IO.FileStream($OutputFile,[System.IO.FileMode]::Create,[System.IO.FileAccess]::Write)
        $streamGZipFileArchive = New-Object -TypeName System.IO.Compression.GZipStream($streamGZipFileOutput,[System.IO.Compression.CompressionMode]::Compress)

        for($iBytes = $streamGZipFileInput.Read($bytesGZipFileBuffer, 0,$bytesGZipFileBuffer.Count);
            $iBytes -gt 0;
            $iBytes = $streamGZipFileInput.Read($bytesGZipFileBuffer, 0,$bytesGZipFileBuffer.Count)){

            $streamGZipFileArchive.Write($bytesGZipFileBuffer,0,$iBytes)
        }

        $streamGZipFileArchive.Dispose()
        $streamGZipFileInput.Close()
        $streamGZipFileOutput.Close()

        Get-Item $OutputFile
    }
    catch { throw $_ }
}


Get-ChildItem -Path $SourceDirectory -Recurse -Exclude "*.7z"|ForEach-Object{
    if($($_.Attributes -band [System.IO.FileAttributes]::Directory) -ne [System.IO.FileAttributes]::Directory){
        #Current file
        $curFile = $_

        #Check the file wasn't modified recently
        if($curFile.LastWriteTime.Date -le (get-date).adddays(-5)){

            $containedDir=$curFile.Directory.FullName.Replace($SourceDirectory,$DestinationDirectory)

            #if target directory doesn't exist - create
            if($(Test-Path -Path "$containedDir") -eq $false){
                New-Item -Path "$containedDir" -ItemType directory
            }

            Write-Host $("Archiving " + $curFile.FullName)
            Compress-File -InputFile $curFile.FullName -OutputFile $("$containedDir\" + $curFile.Name + ".7z")
            Remove-Item -Path $curFile.FullName
        }
    }
}

На самом деле это работает, поскольку создает отдельные архивы для каждого подходящего журнала, но мне нужно «собрать» журналы в один мегаархив, и я не могу понять, как recurse (чтобы получить предметы подуровня) и выполните foreach (чтобы подтвердить возраст), не создавая foreach отдельных архивов.

Я даже не вошел в фазу перемещения и удаления, потому что мне кажется, что я не могу заставить стадию архивирования работать должным образом, но я, конечно, не прочь смириться с этим, как только это выяснится (я Мы уже провели два полных дня, пытаясь понять это!).

Я очень ценю любые предложения! Если я что-то не объяснил или был немного неясен, пожалуйста, дайте мне знать!

РЕДАКТИРОВАТЬ1: Часть требования, о котором я совершенно забыл упомянуть, это то, что мне нужно сохранить структуру в новом месте. Таким образом, новое местоположение будет иметь

  1. C: \ ServerLogs -> C: \ Archive \
  2. C: \ ServerLogs \ App1 -> C: \ Archive \ App1
  3. C: \ ServerLogs \ 2ndApp -> C: \ Archive \ 2ndApp

  4. C: \ Архив

  5. C: \ Archive \ App1 \ archivedlogs.zip
  6. C: \ Archive \ 2ndApp \ archivedlogs.zip
    И я абсолютно не знаю, как указать, что журналы из App1 должны идти в App1.

EDIT2: Для этой последней части я использовал Robocopy - он поддерживает структуру папок, и если вы передадите ему «.zip» в качестве аргумента, он будет выполнять только файлы .zip.

1 Ответ

0 голосов
/ 22 ноября 2018

эта строка $Args = a -mx9 $archive $log, вероятно, нужно, чтобы значение в правой стороне было заключено в двойные кавычки ИЛИ каждая переменная не заключена в кавычки с запятой между ними, чтобы вы получили массив аргументов.

другим методом было бы явное объявление массива аргументов. как то так ...

$ArgList = @(
    'a'
    '-mx9'
    $archive
    $log
    )

Я также рекомендую вам НЕ использовать автоматическое имя $ Var. взгляните на Get-Help about_Automatic_Variables, и вы увидите, что $Args является одним из них. вам настоятельно рекомендуется НЕ использовать какие-либо из них для чего-либо, кроме чтения . писать им сомнительно. [ ухмылка ]

...