Powershell Log Archival Script

2

Lets face it, there’s nothing really exciting about log file management. But like it or not its a pretty common task for DevOps to deal with log files. We’d all like our applications to use a Logging Service like Splunk or Loggly, but until that time comes we need to deal with log files on servers. I developed this script based off the following requirements:

– Log files older than a certain number of days need to be removed from servers.

– Log files need to be archived for a certain number of days before being removed from the servers.

– Archived log files need to be compressed to minimize storage use.

– Archived log files need to be removed after a certain number of days.

– An email notification needs to be sent to administrators with an activity report.

For this script I made use of the Simple Powershell Central Config that I’ve written about before, take a look at that article for how it works. I call the Get-EnvServers function from that script to get the servers to target. I’m also using a helper script that performs zipping of log files, see further down for the details of that script.

The “Script Configuration” Section contains variables that contain the number of days to keep for both log files and log archives. Mail server names, file paths, and a log file name filter are also defined here.

The primary logic of the script searches for files with a LastWriteTime less than the date we set in the config section. If the file name matches the name in the filter, the file gets added to the zip file and also an array of files to be deleted. The zip file is then saved and the files to be deleted are then deleted.

Powershell Log Archival ScriptAn array of objects is used to track the log files that are archived. The ConvertTo-HTML cmdlet is used later to format the array as an HTML table. I’m then manipulating the HTML string to place CSS IDs on alternating rows. I did this to allow the CSS to function in Outlook and other email clients. The Send-MailMessage cmdlet is then used to email out the message.

Powershell Log Archival Script
param (
        [Parameter(Mandatory=$true)]
        [String]$EnvTarget
)

Write-Host " "
Write-Host "                                                            " -BackgroundColor DarkCyan
Write-Host "          Log Archive Script                              " -BackgroundColor DarkCyan
Write-Host "          Environment: $EnvTarget                                  " -BackgroundColor DarkCyan
Write-Host " "

### Include Scripts ###
	Write-Host "Loading Included Scripts"

	if (!(Test-Path "\\atl0fs01\platform\scripts\include-configuration.ps1")){Write-Error "Include Script Not Found: \\atl0fs01\platform\scripts\include-configuration.ps1"; exit}
	. "\\atl0fs01\platform\scripts\include-configuration.ps1"

	if (!(Test-Path "\\atl0fs01\platform\scripts\Include-DotNetZip-Helper.ps1")){Write-Error "Include Script Not Found: \\atl0fs01\platform\scripts\Include-DotNetZip-Helper.ps1"; exit}
	. "\\atl0fs01\platform\scripts\Include-DotNetZip-Helper.ps1"
##########################

# Script Configuration
$ArchivePath = "\\atl0fs01\LogArchive"
$daysToKeep = -2
$daysToKeepArchives = -45
$smtpServer = "mail.tekmortar.com"
$LogPath = "Logs"
$LogNameFilter = "My-App-Log"

# Script Working Variables
$DeleteFiles = @()
$TargetServers = Get-EnvServers $EnvTarget
$counter = 0
$date = Get-Date
$date = $date.AddDays($daysToKeep)
$arrayLogs = @()
$arrayZips = @()
$xcounter = "1"
$zipfile =  new-object Ionic.Zip.ZipFile

Write-Host " "	

foreach ($s in $TargetServers)
{
 	$p = "\\$s\e$"
	$p = Join-Path $p $LogPath
	Write-Host "Adding $p"

	$logs = gci -Path $p | Select-Object Name, FullName, LastWriteTime | Where-Object { $_.LastWriteTime -lt $date }

	if ($logs){
		foreach ($l in $logs){
			$lpath = $l.FullName
			$lname = $l.Name
			$lwrite = $l.LastWriteTime

			if ($lname.Contains($LogNameFilter))
			{
				Write-Host "Archiving $lname - $lwrite"
				$e = $zipfile.AddFile($lpath)

				$counter += 1
				$DeleteFiles += $lpath
				$obj = New-Object psobject -Property @{
					X = $xcounter
  					File = $lname
  					TimeStamp = $lwrite
  					Server = $s
  				}
				if ($xcounter -eq "2"){
					$xcounter = "1"
				}elseif($xcounter -eq "1"){
					$xcounter = "2"
				}
				$arrayLogs += $obj
			}
		}
	}
	Write-Host " "
}

if ($counter -gt 0){
	$datestr = Get-Date -format M-d-yyyy-hh-mm-ss
	$ArchiveFile = $ArchivePath + "\Logs.$EnvTarget.$datestr.zip"
	$zipfile.Save($ArchiveFile)
    $zipfile.Dispose()

	foreach ($f in $DeleteFiles)
	{
		Remove-Item $f -Force
		Write-Host "Deleted $f" -ForegroundColor Yellow
	}
}
Write-Host " "

# Purge Zip Files from the Log Archive
Write-Host "Purging Old Archive Files from $ArchivePath"

$date = Get-Date
$date = $date.AddDays($daysToKeep)

$archives = gci -Path $ArchivePath | Select-Object Name, FullName, LastWriteTime | Where-Object { $_.LastWriteTime -lt $date }

if ($archives){
	foreach ($arch in $archives){
		$lpath = $arch.FullName
		$lname = $arch.Name
		$lwrite = $arch.LastWriteTime

		$obj = New-Object psobject -Property @{
  					File = $lname
  					TimeStamp = $lwrite
  					Server = "atl0fs01"
  				}

		$arrayZips += $obj

		Write-Host "Purging $lname - $lwrite"
		Remove-Item $lpath
	}
}
Write-Host " "

Write-Host "Sending Email"

$a = "<style>"
$a = $a + "BODY{background-color:white;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: #2c3e50;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 5px;border-style: solid;background-color:#34495e;color: #ecf0f1;}"
$a = $a + "TD{border-width: 1px;padding: 5px;border-style: solid;}"
$a = $a + ".EVEN{background-color: #2980b9}"
$a = $a + ".ODD{background-color: #ecf0f1}"
$a = $a + "</style>"

$body = "<b>Performance Log Archive Report</b><p>The following Log Files were archived to $ArchivePath and removed from the Application Server.</p>"

$errstring = $arrayLogs | Select-Object X, Server, File, TimeStamp | ConvertTo-HTML -Head $a | Out-String
$errstring = $errstring.Replace("<tr><td>1</td>", "<tr class='ODD'>")
$errstring = $errstring.Replace("<tr><td>2</td>", "<tr class='EVEN'>")
$errstring = $errstring.Replace("<th>X</th>", "")

$body = $body + $errstring

#Sending email
send-MailMessage -SmtpServer $smtpServer -to "notifications@tekmortar.com" -From "alerts@tekmortar.com" -Subject "Performance Log Archive Report" -Body $body -BodyAsHtml -Priority high
Zip Helper Script

The following script is included to perform file compression of the log files. It uses Ionic.Zip to perform file compression. The script copies the dll locally if it doesn’t exist and then loads the .NET Assembly into memory for use.

$LocalDllPath = "C:\Temp\Ionic.Zip.dll"
$DllPath = "\\atl0fs01\platform\Base\Shared\Ionic.Zip.dll"

### Load SharpSVN ###
if (!(Test-Path $DllPath)){
	Write-Error "Could not locate $DllPath. Check if present and rerun"
	exit
}

if (!(Test-Path $LocalDllPath)){
	Copy-Item $DllPath $LocalDllPath -Force
}

$currentScriptDirectory = Get-Location
[System.IO.Directory]::SetCurrentDirectory($currentScriptDirectory)
$a = [Reflection.Assembly]::LoadFile($LocalDllPath)


My New Stories

March 2016 Web Hosting Deals
Powershell AD Group Management
Troubleshooting 403