How to Set Up IIS Logging and Log Analysis on Windows Server 2012 R2

Internet Information Services (IIS) on Windows Server 2012 R2 maintains detailed access logs recording every HTTP request processed by the web server. These logs are essential for security auditing, performance analysis, troubleshooting application errors, and understanding traffic patterns. IIS supports multiple log formats (W3C Extended, IIS, NCSA), configurable log fields, centralised logging, and log rotation. This guide covers configuring IIS logging via the GUI and PowerShell, customising log fields, implementing centralised logging, and analysing logs with Log Parser and PowerShell.

Prerequisites

IIS must be installed on Windows Server 2012 R2. The IIS Manager role service and the HTTP Logging module must be present. Administrator rights are required. Sufficient disk space on the log destination volume is essential — a busy web server can generate gigabytes of IIS logs daily. Plan log rotation and archival policies before enabling verbose logging.

Step 1: Verify IIS Logging Module is Installed

Ensure the HTTP Logging feature is installed with IIS:

Get-WindowsFeature Web-Http-Logging | Select-Object Name, InstallState
Install-WindowsFeature Web-Http-Logging

Verify the HTTP Logging module is active in IIS:

Get-WebConfigurationProperty -pspath "MACHINE/WEBROOT/APPHOST" -filter "system.webServer/httpLogging" -name "dontLog"

Step 2: Configure IIS Logging via IIS Manager

Open IIS Manager (inetmgr.exe). Select the server node for server-wide settings or an individual site for site-specific logging. Double-click Logging in the Features View.

Configure the following settings: Log Format: W3C is recommended as it supports the widest range of log fields and is compatible with most analysis tools. Log File: Set the directory to a dedicated log volume (e.g., D:IISLogs) rather than the default system drive location. One log file per: Set to Site for multi-site servers to separate logs per site, or Daily for individual sites to create daily-rotated log files. Maximum log file size: Set to prevent any single log file from consuming excessive disk space.

Step 3: Configure Logging via PowerShell

Configure IIS logging settings for all sites using the WebAdministration module:

Import-Module WebAdministration

# Set log directory for default web site
Set-ItemProperty "IIS:SitesDefault Web Site" -Name logFile.directory -Value "D:IISLogs"

# Set log format to W3C
Set-ItemProperty "IIS:SitesDefault Web Site" -Name logFile.logFormat -Value "W3C"

# Set log rotation period to daily
Set-ItemProperty "IIS:SitesDefault Web Site" -Name logFile.period -Value "Daily"

# Enable UTF-8 logging (handles international characters correctly)
Set-ItemProperty "IIS:SitesDefault Web Site" -Name logFile.logTargetW3C -Value "File"

# Apply to all sites
Get-Website | ForEach-Object {
    $siteName = $_.Name
    Set-ItemProperty "IIS:Sites$siteName" -Name logFile.directory -Value "D:IISLogs$siteName"
    Set-ItemProperty "IIS:Sites$siteName" -Name logFile.logFormat -Value "W3C"
    Set-ItemProperty "IIS:Sites$siteName" -Name logFile.period -Value "Daily"
    Write-Host "Configured logging for site: $siteName"
}

Step 4: Customise W3C Log Fields

The default W3C log fields capture the most common HTTP data. Add additional fields for security and performance analysis:

# View current log fields for default site
Get-WebConfigurationProperty "system.applicationHost/sites/site[@name='Default Web Site']/logFile" -Name logExtFileFlags

# Enable additional W3C log fields via appcmd
%windir%system32inetsrvappcmd.exe set config "Default Web Site" /section:system.webServer/httpLogging /dontLog:false /commit:apphost

# Set specific log fields (bitmask values, combine with OR)
# Common flags: Date(1), Time(2), ClientIP(4), UserName(8), SiteName(16), ComputerName(32),
# ServerIP(64), Method(128), UriStem(256), UriQuery(512), HttpStatus(4096), Win32Status(8192),
# BytesSent(131072), BytesRecv(262144), TimeTaken(16384), ServerPort(32768), UserAgent(1048576),
# Referer(4194304), Host(1073741824)
Set-WebConfigurationProperty -pspath "MACHINE/WEBROOT/APPHOST/Default Web Site" -filter "system.webServer/httpLogging" -name "." -value @{dontLog="false"}

Add the X-Forwarded-For header logging for servers behind a load balancer (critical for identifying actual client IPs):

Add-WebConfigurationProperty -pspath "MACHINE/WEBROOT/APPHOST" -filter "system.webServer/httpLogging/customFields" -name "." -value @{logFieldName="X-Forwarded-For"; sourceName="X-Forwarded-For"; sourceType="RequestHeader"}

Step 5: Configure Centralised Logging

Centralised W3C logging writes all IIS site logs to a single set of files rather than per-site files, which simplifies log management on multi-site servers:

# Enable centralised binary logging at server level
Set-WebConfigurationProperty -pspath "MACHINE/WEBROOT/APPHOST" -filter "system.applicationHost/log" -name "centralLogFileMode" -value "CentralBinary"

# Or enable centralised W3C logging
Set-WebConfigurationProperty -pspath "MACHINE/WEBROOT/APPHOST" -filter "system.applicationHost/log" -name "centralLogFileMode" -value "CentralW3C"

# Set centralised log directory
Set-WebConfigurationProperty -pspath "MACHINE/WEBROOT/APPHOST" -filter "system.applicationHost/log/centralW3CLogFile" -name "directory" -value "D:IISLogsCentral"

Step 6: Analyse IIS Logs with PowerShell

Parse IIS W3C log files with PowerShell for quick analysis without third-party tools:

# Parse today's IIS log and find the top 10 requested URLs
$logFile = "D:IISLogsDefault Web Siteu_ex$(Get-Date -Format 'yyMMdd').log"
$entries = Get-Content $logFile | Where-Object {$_ -notmatch "^#"} | ConvertFrom-Csv -Delimiter " " -Header @("date","time","s-sitename","s-computername","s-ip","cs-method","cs-uri-stem","cs-uri-query","s-port","cs-username","c-ip","cs-version","cs(User-Agent)","cs(Cookie)","cs(Referer)","cs-host","sc-status","sc-substatus","sc-win32-status","sc-bytes","cs-bytes","time-taken")

# Top 10 URLs by request count
$entries | Group-Object "cs-uri-stem" | Sort-Object Count -Descending | Select-Object Count, Name -First 10

# 404 errors in the last hour
$entries | Where-Object {$_."sc-status" -eq "404"} | Select-Object date, time, "c-ip", "cs-uri-stem" | Format-Table -AutoSize

# Slow requests (over 5000ms)
$entries | Where-Object {[int]$_."time-taken" -gt 5000} | Select-Object date, time, "cs-uri-stem", "time-taken", "sc-status" | Sort-Object "time-taken" -Descending | Select-Object -First 20

Step 7: Set Up Log Rotation and Archival

Create a scheduled task to compress and archive IIS logs older than a defined retention period:

$archiveScript = @'
$logDir = "D:IISLogs"
$archiveDir = "E:IISLogArchive"
$retentionDays = 30
$archiveAfterDays = 7

# Find log files older than archiveAfterDays and not yet compressed
Get-ChildItem -Path $logDir -Recurse -Filter "*.log" | Where-Object {
    $_.LastWriteTime -lt (Get-Date).AddDays(-$archiveAfterDays)
} | ForEach-Object {
    $archivePath = Join-Path $archiveDir $_.Name
    Compress-Archive -Path $_.FullName -DestinationPath "$archivePath.zip" -Force
    Remove-Item $_.FullName -Force
    Write-Host "Archived: $($_.Name)"
}

# Delete archives older than retention period
Get-ChildItem -Path $archiveDir -Filter "*.zip" | Where-Object {
    $_.LastWriteTime -lt (Get-Date).AddDays(-$retentionDays)
} | Remove-Item -Force
'@

$archiveScript | Out-File "C:ScriptsArchiveIISLogs.ps1" -Encoding UTF8
Register-ScheduledTask -TaskName "IIS Log Archival" -Action (New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NonInteractive -File C:ScriptsArchiveIISLogs.ps1") -Trigger (New-ScheduledTaskTrigger -Daily -At 2am) -RunLevel Highest -User "SYSTEM"

Summary

Properly configured IIS logging on Windows Server 2012 R2 creates a complete audit trail of web server activity that supports security incident investigation, performance troubleshooting, and compliance requirements. By directing logs to a dedicated storage volume, enabling extended W3C log fields including X-Forwarded-For, implementing log rotation, and using PowerShell for regular log analysis, administrators gain ongoing visibility into web application health and can quickly isolate errors, identify attack patterns, and measure response time distribution across all served requests.