IIS Log Management PowerShell Scripts

Each function can be used independently, but some call others as noted below

STANDALONE: Get IIS log file locations


function Get-IISLogPaths {
    Import-Module WebAdministration
    Get-Website | ForEach-Object {
        $logPath = (Get-ItemProperty "IIS:\Sites\$($_.Name)" -Name logFile.directory).Value
        $logPath = $logPath -replace '%SystemDrive%', $env:SystemDrive
        [PSCustomObject]@{
            SiteName = $_.Name
            LogPath = "$logPath\W3SVC$($_.ID)"
            Status = $_.State
        }
    }
}

QUICK START: Get the default website log path


function Get-DefaultLogPath {
    return "C:\inetpub\logs\LogFiles\W3SVC1"
}

REQUIRES LOG PATH: Parse W3C log files (you must provide the path)


function Parse-IISLogs {
    param(
        [Parameter(Mandatory=$true)]
        [string]$LogPath,  # Example: "C:\inetpub\logs\LogFiles\W3SVC1"
        [datetime]$StartDate = (Get-Date).AddDays(-1),
        [datetime]$EndDate = (Get-Date),
        [string]$StatusCode = "*"
    )
    
    Get-ChildItem "$LogPath\*.log" | Where-Object {
        $_.LastWriteTime -ge $StartDate -and $_.LastWriteTime -le $EndDate
    } | ForEach-Object {
        $content = Get-Content $_.FullName
        $fields = ($content | Where-Object { $_ -like "#Fields:*" } | Select-Object -First 1) -replace "#Fields: ", "" -split " "
        
        $content | Where-Object { 
            $_ -notlike "#*" -and $_ -ne "" 
        } | ForEach-Object {
            $values = $_ -split " "
            $logEntry = [ordered]@{}
            
            for ($i = 0; $i -lt $fields.Length; $i++) {
                $logEntry[$fields[$i]] = $values[$i]
            }
            
            if ($logEntry['sc-status'] -like $StatusCode) {
                [PSCustomObject]$logEntry
            }
        }
    }
}

SIMPLE STANDALONE: Get today's logs from default location


function Get-TodaysLogs {
    $logPath = "C:\inetpub\logs\LogFiles\W3SVC1"
    $today = Get-Date -Format "yyMMdd"
    $logFile = Get-ChildItem "$logPath\ex$today.log" -ErrorAction SilentlyContinue
    
    if ($logFile) {
        Get-Content $logFile.FullName | Where-Object { $_ -notlike "#*" -and $_ -ne "" } | Select-Object -Last 20
    } else {
        Write-Host "No log file found for today at $logPath" -ForegroundColor Yellow
    }
}

3. Get today's error logs (4xx, 5xx status codes)


function Get-IISErrors {
    param([string]$SiteName = "Default Web Site")
    
    $site = Get-Website -Name $SiteName
    $logPath = (Get-ItemProperty "IIS:\Sites\$SiteName" -Name logFile.directory).Value
    $logPath = $logPath -replace '%SystemDrive%', $env:SystemDrive
    $fullPath = "$logPath\W3SVC$($site.ID)"
    
    Parse-IISLogs -LogPath $fullPath -StatusCode "[45]*" | 
        Group-Object 'sc-status' | 
        Sort-Object Count -Descending |
        Select-Object Name, Count, @{Name='URLs'; Expression={($_.Group | Select-Object -First 5 'cs-uri-stem').('cs-uri-stem')}}
}

4. Monitor real-time IIS logs


function Watch-IISLogs {
    param(
        [string]$SiteName = "Default Web Site",
        [int]$TailLines = 10
    )
    
    $site = Get-Website -Name $SiteName
    $logPath = (Get-ItemProperty "IIS:\Sites\$SiteName" -Name logFile.directory).Value
    $logPath = $logPath -replace '%SystemDrive%', $env:SystemDrive
    $logFile = Get-ChildItem "$logPath\W3SVC$($site.ID)" -Filter "*.log" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
    
    Get-Content $logFile.FullName -Tail $TailLines -Wait
}

5. Configure W3C logging format


function Set-IISLogFormat {
    param(
        [string]$SiteName = "Default Web Site",
        [string[]]$Fields = @('date', 'time', 'c-ip', 'cs-username', 'cs-method', 'cs-uri-stem', 'cs-uri-query', 'sc-status', 'sc-bytes', 'cs-bytes', 'time-taken', 'cs(User-Agent)', 'cs(Referer)')
    )
    
    Import-Module WebAdministration
    Set-WebConfigurationProperty -Filter "system.webServer/httpLogging" -PSPath "IIS:\Sites\$SiteName" -Name "selectiveLogging" -Value "LogAll"
    
    # Set log fields
    $logFields = $Fields -join ','
    Set-WebConfigurationProperty -Filter "system.webServer/httpLogging" -PSPath "IIS:\Sites\$SiteName" -Name "logExtFileFlags" -Value $logFields
}

6. Analyze top IPs and URLs


function Get-IISTopStats {
    param(
        [string]$SiteName = "Default Web Site",
        [int]$TopCount = 10
    )
    
    $site = Get-Website -Name $SiteName
    $logPath = (Get-ItemProperty "IIS:\Sites\$SiteName" -Name logFile.directory).Value
    $logPath = $logPath -replace '%SystemDrive%', $env:SystemDrive
    $fullPath = "$logPath\W3SVC$($site.ID)"
    
    $logs = Parse-IISLogs -LogPath $fullPath
    
    Write-Host "Top $TopCount IPs:" -ForegroundColor Green
    $logs | Group-Object 'c-ip' | Sort-Object Count -Descending | Select-Object -First $TopCount Name, Count
    
    Write-Host "`nTop $TopCount URLs:" -ForegroundColor Green
    $logs | Group-Object 'cs-uri-stem' | Sort-Object Count -Descending | Select-Object -First $TopCount Name, Count
    
    Write-Host "`nTop $TopCount User Agents:" -ForegroundColor Green
    $logs | Group-Object 'cs(User-Agent)' | Sort-Object Count -Descending | Select-Object -First $TopCount Name, Count
}

Usage Examples:

SIMPLE - Just see today's logs:

Get-TodaysLogs

FIND LOG PATHS - If you don't know where logs are:

Get-IISLogPaths

PARSE SPECIFIC PATH - HERE'S HOW YOU ADD THE PATH:

Parse-IISLogs -LogPath "C:\inetpub\logs\LogFiles\W3SVC1"

OR if your logs are on F drive:

Parse-IISLogs -LogPath "F:\inetpub\logs\LogFiles\W3SVC1"

REAL EXAMPLES OF HOW TO TYPE THE COMMANDS:

1. Copy and paste this exact line in PowerShell:

Parse-IISLogs -LogPath "C:\inetpub\logs\LogFiles\W3SVC1"

2. Or if you want only errors:

Parse-IISLogs -LogPath "C:\inetpub\logs\LogFiles\W3SVC1" -StatusCode "4*"

3. Or just today's logs:

Parse-IISLogs -LogPath "C:\inetpub\logs\LogFiles\W3SVC1" -StartDate (Get-Date).Date

The path goes AFTER -LogPath and in quotes!