functions/Compress-LogDirectory.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
<#
.Synopsis
Compress log files older than the current month in a given directory or the IIS log directories.
.Description
Compress log files older than the current month in a given directory or the IIS log directories.
Zip archives with the name ZipArchiveYYYY.zip are created in the log directories, where YYYY is the year of change of the archived file.
By default, only files with the extension ".log" are archived. This extension, the month, the archive name and recursive processing of subdirectories can be selected by parameters.
 
A regular start via scheduled tasks can be set up at a command prompt for example via:
 
schtasks.exe /Create /TN "Archive IIS log files" /TR "Powershell.exe -NoProfile -Command \"Compress-LogDirectory -IIS\"" /SC MONTHLY /D 15 /ST 21:15 /RU SYSTEM /RL HIGHEST /F
.Parameter Path
Path of the log directory (also via pipeline)
.Parameter IIS
IIS log directories are processed
.Parameter Filter
Filter of the files to be archived
.Parameter MonthBack
Number of months in the past for checking the change date
.Parameter ArchiveName
Name part of the archives
.Parameter Recurse
Recursive processing of subdirectories of $Path
.Inputs
Directory path
.Outputs
None
.Example
Compress-LogFileDirectory -Path "C:\LogFiles" -Filter "*.*" -MonthBack 3 -ArchiveName "zip"
 
Archives all files in directory C:\LogFiles which are 3 months older than the current month in the archives "zipYYYY.zip" (YYYY = year of change of the respective file).
.Example
Compress-LogFileDirectory -IIS
 
Archives all files in IIS log directories older than the current month in the archives "ZipArchiveYYYY.zip" (YYYY = year of change of the respective file) in the log directories.
.Notes
Author: Markus Scholtes
Version: 1.0
Date: 2019-05-06
#>

function Compress-LogDirectory
{ Param([Parameter(Position=1,Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName,ParameterSetName="PerPath")][Alias("FullName")]$Path,
        [Parameter(Position=1,Mandatory,ParameterSetName="ForIIS")][SWITCH]$IIS,
        [Parameter(Position=2,ParameterSetName="PerPath")][STRING]$Filter = "*.log",
        [Parameter(Position=3,ParameterSetName="PerPath")][Parameter(Position=2,ParameterSetName="ForIIS")][INT]$MonthBack = 0,
        [Parameter(Position=4,ParameterSetName="PerPath")][Parameter(Position=3,ParameterSetName="ForIIS")][STRING]$ArchiveName = "ZipArchive",
        [Parameter(Position=5,ParameterSetName="PerPath")][SWITCH]$Recurse
    )

    function Compress-LogDirectory
    { # directory names can be passed per parameter or pipeline
        Param(
            [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)][Alias("FullName")]$Path,
            [STRING]$Filter = "*.log",
            [INT]$MonthBack = 0,
            [STRING]$ArchiveName = "ZipArchive"
        )

        # compute the date of the first day after the month to archive
        $DateBack = (Get-Date).AddMonths(-1*$MonthBack)
        $DateFilter = [DateTime]::new($DateBack.Year, $DateBack.Month, 1)

        Write-Output ("-"*80)
        # process only if path is a directory
        if (Test-Path -Path $Path -PathType Container)
        {
            if ($Path -is [STRING])
            { # if path is of type string, convert to DirectoryInfo
                $Path = Get-Item -Path $Path
            }

            Write-Output "Processing directory $($Path.FullName)"
            # retrieve filtered files older then $DateFilter
            $FILES = Get-ChildItem -Path $Path -Filter $Filter -File | Where-Object { $_.LastWriteTime -lt $DateFilter }
            if ($FILES.Count -gt 0)
            { # if files found fitting to filter
                Write-Output "Found $($FILES.Count) files to compress."
                $FILES | ForEach-Object { # for each file: compute archive name to last write time, add file to archive and delete file
                    try {
                        $NAMEWITHYEAR = Join-Path -Path $Path.FullName -ChildPath "$ArchiveName$($_.LastWriteTimeUtc.Year.ToString()).zip"

                        if ($_.FullName -ne $NAMEWITHYEAR)
                        { # only compress if not archive file itself
                            Write-Output "Compressing file $($_.Name) to archive $NAMEWITHYEAR"
                            Compress-Archive -Path $_.FullName -DestinationPath $NAMEWITHYEAR -Update:(Test-Path $NAMEWITHYEAR) -CompressionLevel Optimal -ErrorAction Stop

                            Write-Output "Removing file $($_.Name)"
                            Remove-Item -Path $_.FullName
                        }
                        else
                        { # archive file itself is ignored
                            Write-Output "Ignoring archive file $NAMEWITHYEAR"
                        }
                    }
                    catch { # error occured on archiving or deleting
                        Write-Error $PSItem.Exception.Message
                    }
                }
            }
            else
            { # no files to archive found
                Write-Output "Found no files to compress."
            }
        }
        else
        {    # file found or path does not exist, error and return
            if (Test-Path -Path $Path)
            { # file found
                Write-Error "$Path is a file."
            }
            else
            { # path does not exist
                Write-Error "$Path does not exist."
            }
        }
    }


    if ($IIS)
    { # process IIS logfile directories
        try { # load IIS module
            Import-Module WebAdministration -ErrorAction Stop
        }
        catch { # cannot load IIS module
            Write-Error "Cannot load IIS Powershell module, are IIS and administrative rights present?"
            return
        }

        ForEach ($WEBSITE in (Get-Website))
        { # iterate through websites
            $IISLOGDIR = $WEBSITE.LogFile.Directory + "\W3SVC" + $WEBSITE.Id -replace "%SystemDrive%", $ENV:SystemDrive -replace "%LOGFILEDIR%", $ENV:LOGFILEDIR
            Write-Output "Processing log directory $IISLOGDIR of web site '$($WEBSITE.Name)'"
            Compress-LogDirectory -Path $IISLOGDIR -Filter "*.log" -MonthBack $MonthBack -Archive $ArchiveName
        }
    }
    else
    { # process directory in parameter -Path
        # archive logs in directory $Path
        Compress-LogDirectory -Path $Path -Filter $Filter -MonthBack $MonthBack -Archive $ArchiveName

        if ($RECURSE)
        { # archive logs in subdirectories too
            Get-ChildItem -Path $Path -Directory -Recurse | ForEach-Object { Compress-LogDirectory -Path $_.FullName -Filter $Filter -MonthBack $MonthBack -Archive $ArchiveName }
        }
    }
}