Compressing IIS and Windows Media Server Logs with PowerShell

The PowerShell Community Extensions Project shipped a Write-GZip cmdlet which made me think that it's time to re-write the trusty CompressLogFiles.vbs file I've been using for a while.  After grappling with the square brackets in the WMS [Global] folder I think I finally have a viable solution.  Since many folks have IIS servers with logs rolling daily here's a great way to cut down on disk space (maybe I'll look at writing a module for IIS 7 next month to hook into the log rolling):

#===========================================================================
# Compress all log files older than today within a directory structure.
#===========================================================================
# Syntax: Compress-LogFiles.ps1 {LogPath}
#===========================================================================
# Revision History:
#   1.0 - 31-Jan-08 - Initial creation.
#                   - Colin Bowern
#===========================================================================
# Stop the script in the event of an error
$ErrorActionPreference = "Stop";
trap [System.Exception]
{
    Write-Host $_.Exception.ToString();
    
    $EventLog = New-Object System.Diagnostics.EventLog
    $EventLog.Set_Log("Windows PowerShell")
    $EventLog.Set_Source("PowerShell")
    $EventLog.WriteEntry($_.Exception.ToString(), "Error")
}

# Load Dependencies
if (!(Test-Path Variable:__PscxProfileRanOnce))
{
    Write-Error "PowerShell Community Extensions is required for this script.";
}

# Parse Command Line Arguments
if($args.length -ne 1)
{
    Write-Host "NAME";
    Write-Host "    Compress-LogFiles.ps1";
    Write-Host "";
    Write-Host "SYNOPSIS";
    Write-Host "    Compress all log files older than today within a directory structure.";
    Write-Host "";
    Write-Host "SYNTAX";
    Write-Host "    Compress-LogFiles.ps1 {LogPath}";
    Write-Host "";
    Write-Host "EXAMPLE";
    Write-Host "    Compress-LogFiles.ps1 D:\LogFiles";
    Write-Host "";
    $ErrorActionPreference = "ContinueSilent";
    Write-Error "Invalid number of command line arguments." -Category SyntaxError;
    Break;
}

$LogPath = $args[0];

#===========================================================================
# For Each *.log File in $LogPath

$IISLogFileToday = [String]::Format("ex{0}.log", [DateTime]::Now.ToString("yyyyMMdd"));
$WMSLogFileToday = [String]::Format("wms_{0}.log", [DateTime]::Now.ToString("yyyyMMdd"));

[array]$LogFiles = Get-ChildItem -Path $LogPath -Recurse -Include "ex*.log",
	"wms*.log", "````[Global````]" -Exclude $IISLogFileToday, $WMSLogFileToday,
	"httperr*.log", "httperr"

if($LogFiles.Count -gt 0)
{
    $Index = 0;
    foreach ($LogFile in $LogFiles)
    {
        Write-Progress -Id 1 -activity "Compressing Files" -status $LogFile.FullName
			-percentComplete($Index / $LogFiles.Count * 100);
        if(Test-Path ("{0}.gz" -f ([Management.Automation.WildcardPattern]::Escape($LogFile.FullName))))
        {
			Write-Error "Destination file already exists." -Category ResourceExists;
		}
        Write-GZip ([Management.Automation.WildcardPattern]::Escape($LogFile.FullName)) -Level 9;
        if(Test-Path ("{0}.gz" -f ([Management.Automation.WildcardPattern]::Escape($LogFile.FullName))))
        {
            Remove-Item ([Management.Automation.WildcardPattern]::Escape($LogFile.FullName))
        }
        $Index += 1;
    }
}
else
{
	Write-Host "There were no log files found that required processing.";
}
#===========================================================================

Comments Subscribe to Post Comments Feed

Radek Mackowiak said:

Hello Colin,

thank you very much for this little script.

I'll have to change this part

"!(Test-Path Variable:__PscxProfileRanOnce)"

to this

"(Test-Path Variable:__PscxProfileRanOnce)"

to get it working.

Now I'll have to change

"older than today" to "older than a week"

;-)

Radek Mackowiak said:

Boah, i don't get it.

My logfiles are all saved in this format

u_ex071001.log

u_ex071002.log

The last 2 numbers aren't days, they are parts, because I'm saving the logfiles every week

I'm testing only with this 2 files at the moment.

So, i'll changed this

[String]::Format("u_ex{0}.log", [DateTime]::Now.ToString("yyyyMMdd"));

to this

Get-ChildItem -Path $LogPath -Recurse -Include "u_ex*.log" | sort-object -property LastWriteTime | select-object name -last 1 |  select name | fw

to get this string

u_ex071002.log

But this doesn't have an effect and all logfiles will be zipped

Someone has an idea to exclude the last modified logfile

Ps: Nice Blog

Radek Mackowiak said:

Ok I have it.

This modification of colins Script do exactly what I want:

Compress all logfiles Compress all log files older than "today" and get this via lastwrite time

$ErrorActionPreference = "Stop";

trap [System.Exception]

{

   Write-Host $_.Exception.ToString();

   $EventLog = New-Object System.Diagnostics.EventLog

   $EventLog.Set_Log("Windows PowerShell")

   $EventLog.Set_Source("PowerShell")

   $EventLog.WriteEntry($_.Exception.ToString(), "Error")

}

# Load Dependencies

if ((Test-Path Variable:__PscxProfileRanOnce))

{

   Write-Error "Die PowerShell Community Extensions werden für dieses Script benoetigt.";

}

# Parse Command Line Arguments

if($args.length -ne 1)

{

   Write-Host "Name";

   Write-Host "    Compress-LogFiles.ps1";

   Write-Host "";

   Write-Host "Aufgabe";

   Write-Host "    Komprimiert alle Logfiles die aelter sind als die Heutige.";

   Write-Host "";

   Write-Host "Syntax";

   Write-Host "    Compress-LogFiles.ps1 {LogPath}";

   Write-Host "";

   Write-Host "Beispiel";

   Write-Host "    Compress-LogFiles.ps1 D:\LogFiles";

   Write-Host "";

   $ErrorActionPreference = "ContinueSilent";

   Write-Error "Es wird ein Argument mit dem LogPath erwartet" -Category SyntaxError;

   Break;

}

$curTime = [System.DateTime]::get_now()

$LogPath = $args[0];

[array]$LogFiles = Get-ChildItem -Path $LogPath -Recurse -Include "u_ex*.log"

if($LogFiles.Count -gt 0)

{

   $Index = 0;

   foreach ($LogFile in $LogFiles)

   {

       Write-Progress -Id 1 -activity "Compressing Files" -status $LogFile.FullName

       if(Test-Path ("{0}.gz" -f ([Management.Automation.WildcardPattern]::Escape($LogFile.FullName))))

       {

Write-Error "Destination file already exists." -Category ResourceExists;

}

if ($LogFile.LastWriteTime -le $curTime.Add("-1"))

{

        Write-GZip ([Management.Automation.WildcardPattern]::Escape($LogFile.FullName)) -Level 9;

        if(Test-Path ("{0}.gz" -f ([Management.Automation.WildcardPattern]::Escape($LogFile.FullName))))

        {

            Remove-Item ([Management.Automation.WildcardPattern]::Escape($LogFile.FullName))

        }

}

       $Index += 1;

   }

}

else

{

Write-Host "Es wurde KEINE unkomprimierten Logfiles gefunden";

}

Prasanth Rowlo said:

Hey Collin,

I don have complete idea on poweshell scripting. can I have a script to compress/zip and to delete iis logs older than 7days.

Prasanth Rowlo said:

You can mail me at prasanth.rowlo@bt.com

Have Your Say