【问题标题】:how to compress log files older than 30 days in windows?如何在 Windows 中压缩超过 30 天的日志文件?
【发布时间】:2019-05-13 10:20:40
【问题描述】:

我写下面的 powershell 脚本来压缩超过 30 天的日志:-

$LastWrite=(get-date).AddDays(-30).ToString("MM/dd/yyyy")

Get-ChildItem -Filter "server.log*" -Recurse -File | Where-Object 
{$_.LastWriteTime -le $LastWrite} 

现在,我无法在 powershell 中获取压缩命令,通过它我可以压缩(zip/tar)超过 30 天的 server.log* 文件。 期待一个我可以通过在上述命令中添加管道符号来使用的命令。

【问题讨论】:

  • 您使用的是哪个 PowerShell 版本?

标签: windows powershell scripting


【解决方案1】:

如果您拥有 PowerShell 版本 5 或更高版本,则可以使用 Compress-Archive cmdlet 压缩文件:

$LastWrite = (get-date).AddDays(-30)

$Files = Get-ChildItem -Filter "server.log*" -Recurse -File | Where-Object {$_.LastWriteTime -le $LastWrite}

ForEach ($File in $Files) {
    $File | Compress-Archive -DestinationPath "$($File.fullname).zip"
}

【讨论】:

  • .ToString("MM/dd/yyyy") 不需要。 LastWriteTimeDateTime类型,和Get-Date的输出一样,所以可以直接比较。
  • 以上答案在powershell 5或更高版本的情况下很有用。对于以下版本,我使用了以下压缩命令:- $File | jar -cvMf "$($File.fullname).zip" $File
【解决方案2】:

如果您有旧版本的 Powershell,您可以使用 ZipFileExtensions 的 CreateEntryFromFile 方法,但如果您想要一个无人看管的健壮脚本,则需要考虑很多因素。

在测试为此目的而开发的script 几个月后,我遇到了一些问题,使这个小问题变得更加复杂:

  1. 是否会锁定任何文件?如果是这样,CreateEntryFromFile 可能会失败。
  2. 您知道您可以在 Zip 存档中拥有同一文件的多个副本吗?提取它们更难,因为您不能将它们放在同一个文件夹中。我的脚本检查文件路径和存档文件时间戳(由于 Zip 格式的日期精度丢失,+/- 2 秒)以确定它是否已经存档,并且不会创建重复。
  3. 文件是在夏令时的时区创建的吗? Zip 格式不保留该属性,并且在未压缩时可能会损失或增加一个小时。
  4. 如果已成功存档,是否要删除原件?
  5. 如果由于文件锁定/丢失或路径过长而失败,是否应该继续该过程?
  6. 任何错误都会导致您无法使用 zip 文件吗?您需要 Dispose() 存档以完成它。
  7. 您要保留多少档案?我更喜欢每个运行月一个,向现有 zip 添加新条目。
  8. 是否要保留相对路径?这样做将部分消除 zip 文件中的重复问题。

如果您不关心这些问题并且您拥有 Powershell 5,Mark Wragg 的脚本应该可以工作,但它会为每个日志创建一个 zip,这可能不是您想要的。

这是脚本的当前版本 - 以防 GitHub 不可用:

#Sends $FileSpecs files to a zip archive if they match $Filter - deleting the original if $DeleteAfterArchiving is true. 
#Files that have already been archived will be ignored. 
param (
   [string] $ParentFolder = "$PSScriptRoot", #Files will be stored in the zip with path relative to this folder
   [string[]] $FileSpecs = @("*.log","*.txt","*.svclog","*.log.*"), 
   $Filter = { $_.LastWriteTime -lt (Get-Date).AddDays(-7)}, #a Where-Object function - default = older than 7 days
   [string] $ZipPath = "$PSScriptRoot\archive-$(get-date -f yyyy-MM).zip", #create one archive per run-month - it may contain older files 
   [System.IO.Compression.CompressionLevel]$CompressionLevel = [System.IO.Compression.CompressionLevel]::Optimal, 
   [switch] $DeleteAfterArchiving = $true,
   [switch] $Verbose = $true,
   [switch] $Recurse = $true
)
@( 'System.IO.Compression','System.IO.Compression.FileSystem') | % { [void][System.Reflection.Assembly]::LoadWithPartialName($_) }
Push-Location $ParentFolder #change to the folder so we can get relative path
$FileList = (Get-ChildItem $FileSpecs -File -Recurse:$Recurse  | Where-Object $Filter) #CreateEntryFromFile raises UnauthorizedAccessException if item is a directory
$totalcount = $FileList.Count
$countdown = $totalcount
$skipped = @()
Try{
    $WriteArchive = [IO.Compression.ZipFile]::Open( $ZipPath, [System.IO.Compression.ZipArchiveMode]::Update)
    ForEach ($File in $FileList){
        Write-Progress -Activity "Archiving files" -Status  "Archiving file $($totalcount - $countdown) of $totalcount : $($File.Name)"  -PercentComplete (($totalcount - $countdown)/$totalcount * 100)
        $ArchivedFile = $null
        $RelativePath = (Resolve-Path -LiteralPath "$($File.FullName)" -Relative) -replace '^.\\'
        $AlreadyArchivedFile = ($WriteArchive.Entries | Where-Object {#zip will store multiple copies of the exact same file - prevent this by checking if already archived. 
                (($_.FullName -eq $RelativePath) -and ($_.Length -eq $File.Length) )  -and 
                ([math]::Abs(($_.LastWriteTime.UtcDateTime - $File.LastWriteTimeUtc).Seconds) -le 2) #ZipFileExtensions timestamps are only precise within 2 seconds. 
            })     
        If($AlreadyArchivedFile -eq $null){
            If($Verbose){Write-Host "Archiving $RelativePath $($File.LastWriteTimeUtc -f "yyyyMMdd-HHmmss") $($File.Length)" }
            Try{
                $ArchivedFile = [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($WriteArchive, $File.FullName, $RelativePath, $CompressionLevel)
            }Catch{
                Write-Warning  "$($File.FullName) could not be archived. `n $($_.Exception.Message)"  
                $skipped += [psobject]@{Path=$file.FullName; Reason=$_.Exception.Message}
            }
            If($File.LastWriteTime.IsDaylightSavingTime() -and $ArchivedFile){#HACK: fix for buggy date - adds an hour inside archive when the zipped file was created during PDT (files created during PST are not affected).  Not sure how to introduce DST attribute to file date in the archive. 
                $entry = $WriteArchive.GetEntry($RelativePath)    
                $entry.LastWriteTime = ($File.LastWriteTime.ToLocalTime() - (New-TimeSpan -Hours 1)) #TODO: This is better, but maybe not fully correct. Does it work in all time zones?
            }
        }Else{#Write-Warning "$($File.FullName) is already archived$(If($DeleteAfterArchiving){' and will be deleted.'}Else{'. No action taken.'})" 
            Write-Warning "$($File.FullName) is already archived - No action taken." 
            $skipped += [psobject]@{Path=$file.FullName; Reason="Already archived"}
        }
        If((($ArchivedFile -ne $null) -and ($ArchivedFile.FullName -eq $RelativePath)) -and $DeleteAfterArchiving) { #delete original if it's been successfully archived. 
            Try {
                Remove-Item $File.FullName -Verbose:$Verbose
            }Catch{
                Write-Warning "$($File.FullName) could not be deleted. `n $($_.Exception.Message)"
            }
        } 
        $countdown = $countdown -1
    }
}Catch [Exception]{
    Write-Error $_.Exception
}Finally{
    $WriteArchive.Dispose() #close the zip file so it can be read later 
    Write-Host "Sent $($totalcount - $countdown - $($skipped.Count)) of $totalcount files to archive: $ZipPath"
    $skipped | Format-Table -Autosize -Wrap
}
Pop-Location

这是一个命令行,它将压缩当前文件夹下所有超过 30 天的 server.log* 文件:

.\ArchiveOldLogs.ps1 -FileSpecs @("server.log*") -Filter { $_.LastWriteTime -lt (Get-Date).AddDays(-30)}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-04
    • 2013-12-04
    • 2013-06-22
    • 2013-12-08
    • 1970-01-01
    • 1970-01-01
    • 2015-08-15
    • 1970-01-01
    相关资源
    最近更新 更多