IIS Log File Maintenance

I am in the process of changing my server build-out scripts to DSC and am being forced to deal with an IIS Log File Maintenance routine, I cobbled together years back.

Right now, it is a separate script (one for 2003, one for 2008, there was some incompatibility with 2012 I haven’t dealt with) that I run on all servers with IIS. The script finds the log drive, creates a new Log folder, creates an Archive and a Bin folder within that, puts an archiving/purging script and the Info-Zip executable in the bin folder, then creates a scheduled task to run the script every night. I’d like to also add changing all IIS log paths to this location to the script.

Before I go any further (custom DSC Resource?) I wanted to ask the community, how are you handling IIS’s lack of a built-in log maintenance solution?

This seems like a basic feature that IIS should have by now. Maybe I’m missing something.

Thanks,
Nathan

Good God, I was literally typing a note to Steve Murawski about this. It says:

I’m running into a thing where people read “configuration” and think “provisioning.” So they think, “well, DSC is only useful when I set up a server or need to change its role, but I still need PowerShell scripts for maintenance.” Which isn’t true.

I’d like a simple resource that deals with file archiving and rotation.

E.g., specify a source path, an optional archive path, a max file age, and an optional max archive file age. Also specify an archive action, “Archive” or “Delete.” There’d be no “ensure.”

If you specify Delete, then any files in the source path older than MaxFileAge get deleted.

if you specify Archive, then any files in the source path older than MaxFileAge get moved to the archive path; any files in the archive path older than MaxArchiveFileAge get deleted.

Simple (hopefully), but demonstrates that ongoing maintenance is also a form of “configuration.”

Which is basically what you’re asking for. So there’s nothing built in, but a custom DSC resource would indeed do it, and would be a great way to go.

hi,

Maybe I am missing your point, however are you talking about how you should configure logfile rollover/retention so that it does not fill up your disk or are you talking about what IIS logs into the logfile?

Log file management - e.g., rollover and archival. The end point was, no, IIS doesn’t do it natively, and yes, a custom DSC resource would deb a good way to go about it, if your servers have PowerShell v4 installed.

Sorry, yes, roll-over and retention is indeed what I am after.

hi again,

Don is almost correct :slight_smile: We have rollover natively in IIS, however no achiving of items of an certain age. So custom DSC it is then or you could use a DSC script Resource while you develop you custom DSC resource.

To get you started (below code will give you the current logfile settings):

Import-Module WebAdministration $site = get-item IIS:\Sites\MyNewSite $site.logfile

I snipped the above code from this link:

http://stackoverflow.com/questions/4626791/powershell-command-to-set-iis-logging-settings

Yes, IIS does have some facility for doing file roll-overs, but my old script actually Zipped the files daily and stored them in an archive folder for X days before deleting them.

I think the quick and dirty solution will be to:

  • Create the new Log Folder, outside of the System Drive, with the File Resource.
  • Set the IIS hourly roll-over and change the logging path to the new location (thanks for the code), looks like this needs to be a Script Resource for now.
  • Then create a scheduled task with a Script Resource to simply purge the log folder. Probably with my old standby below...

powershell.exe -command "&{Get-ChildItem e:\logs\* -Include ex*.log -Recurse  | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-7)} | Remove-Item }"

hi,

Looks like a good plan. Best of luck :slight_smile:

Cheers

I’m close… The LCM doesn’t seem to have permission to create the Scheduled Job. The following code returns, “This event indicates that a non-terminating error was thrown when DSCEngine was executing Set-TargetResource on MSFT_ScriptResource provider. FullyQualifiedErrorId is UnauthorizedAccessToRegisterScheduledJobDefinition,Microsoft.PowerShell.ScheduledJob.RegisterScheduledJobCommand. ErrorMessage is An access denied error occurred when registering scheduled job definition PurgeLogFolder. Try running Windows PowerShell with elevated user rights; that is, Run As Administrator…”

configuration LogDirectory { param ([string[]]$Node) node $Node { Script LogDirectoryScript { GetScript = { $job = Get-ScheduledJob PurgeLogFOlder [ordered]@{ FolderPresent= (Test-Path C:\log) JobId = $job.Id JobName = $job.Name JobEnabled = $job.Enabled JobCommand = $job.Command } }
        SetScript = {
            # Create directory
            if ( -not (Test-Path C:\log)) { 
                New-Item -ItemType Directory -Path C:\log
            }

            # Change permissions such that any user can write.
            $acl = (Get-Item C:\log).GetAccessControl('Access')
            $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule("Users","Write", "Allow")))
            Set-Acl -Path C:\log -AclObject $acl | Out-Host

            # Schedule purge task
            if ([bool](Get-ScheduledJob PurgeLogFOlder -ErrorAction SilentlyContinue)) {
                Unregister-ScheduledJob -Name PurgeLogFolder
            }
            $script = {Get-ChildItem C:\log\* -Include ex*.log -Recurse  | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-7)} | Remove-Item}
            $trigger = New-JobTrigger -Daily -At 23:59:59
            Register-ScheduledJob -Name PurgeLogFolder -ScriptBlock $script -Trigger $trigger
        }

        TestScript = {
            (Test-Path C:\log) -and [bool](Get-ScheduledJob PurgeLogFOlder -ErrorAction SilentlyContinue)
        }
    }
}

}

Lcm runs as system, so it might well not. You might need to provide a credential.

I knew LCM ran as System. It seemed like LCM should have been able to create a Scheduled Job, as System, to run as System, and I’d be all set.

As you can tell, I was trying to skate around the whole “having to create an account just to purge files” thing… (Why isn’t this built into IIS???)

In the end… I cheated. I just do not have time, at the moment, to take this any further.

Thank you for your help!

Ironically, I can only use this on our Server 2008 R2 servers. Our current version of ESX does not support 2012 R2. So the 2012 servers that I hoped to configure with DSC, will have to wait. (Don, your rant the other night came to mind when I discovered this situation.)

configuration LogDirectory { param ( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string[]]$Node ) node $Node { Script LogDirectoryScript { GetScript = { $result = (Test-Path 'E:\log') -and (schtasks.exe /query /TN Purge_Log_Folder | Select-String Purge_Log_Folder -Quiet) return @{ GetScript = $GetScript SetScript = $SetScript TestScript = $TestScript Result = $result } } SetScript = { Write-Verbose 'Creating log directory.' if ( -not (Test-Path 'E:\log')) { New-Item -ItemType Directory -Path 'E:\log' } Write-Verbose 'Changing permissions to log directory such that any user can write, but only an administrator can read or modify.' $acl = (Get-Item 'E:\log').GetAccessControl('Access') $acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule('Users','Write', 'Allow'))) Set-Acl -Path 'E:\log' -AclObject $acl | Out-Host Write-Verbose 'Scheduling purge task.' $script = 'Get-ChildItem E:\log\* -Include ex*.log -Recurse | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-7)} | Remove-Item' Set-Content -Path C:\Windows\Purge_Log_Folder.ps1 -Value $script $task = 'Powershell.exe -NoProfile -ExecutionPolicy RemoteSigned -File C:\Windows\Purge_Log_Folder.ps1' SCHTASKS /CREATE /TN Purge_Log_Folder /TR $task /SC DAILY /ST 23:59 /RU SYSTEM /F | Out-Host Write-Verbose 'Configuring IIS' # Default Log File Settings for Web Sites <logFile> # http://www.iis.net/configreference/system.applicationhost/sites/sitedefaults/logfile Import-Module WebAdministration Set-WebConfigurationProperty '/system.applicationHost/sites/siteDefaults' -name logFile -value @{ directory = 'E:\log' localTimeRollover ='true' period = 'Hourly' } } TestScript = { (Test-Path 'E:\log') -and (schtasks.exe /query /TN Purge_Log_Folder | Select-String Purge_Log_Folder -Quiet) } } } }

I know this is not PowerShell but I have been using this service for years and years…

http://www.iislogs.com/

It’s a third party utility that runs as a service and manages archiving your IIS Logs for you. It is actually on my RADAR to get around to making a PowerShell equivelent which I am working on but I wanted to use built in Windows ZIP and not 7zip or some 3rd party command line ZIP tool. I have the COM Object for ZIPPING but just haven’t had time to finish the script. Probably because this 3rd party tool works really well and has served my company for many years.

-VERN

Here’s my take on this, which also includes some sanity checking on the log file names (optional). Guess that has been covered, though, didn’t realize when writing the article.

Automatically delete old IIS logs with PowerShell

I run this script weekly on an IIS server via the task scheduler.

# Script to be run weekly by task scheduler to cleanup IIS files
# greater than 30 days old.
#
# Bob McCoy 3/27/14

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

# Clean up old log files
Get-ChildItem C:\inetpub\logs\LogFiles -File -Recurse | where LastWriteTime -lt $start | Remove-Item

# Get rid of bounced mail files
Get-ChildItem C:\inetpub\mailroot\Badmail -File -Recurse | where LastWriteTime -lt $start | Remove-Item