Created
June 5, 2026 14:52
-
-
Save tcartwright/2415882c40f6d71ff136eb0d5e8f7f89 to your computer and use it in GitHub Desktop.
POWERSHELL: Enforce IIS standard logging fields
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Clear-Host | |
| #Requires -RunAsAdministrator | |
| Import-Module WebAdministration -ErrorAction Stop | |
| $apphost = "MACHINE/WEBROOT/APPHOST" | |
| $standardFlags = "Date,Time,ClientIP,UserName,SiteName,ComputerName,ServerIP,Method,UriStem,UriQuery,HttpStatus,HttpSubStatus,Win32Status,BytesSent,BytesRecv,TimeTaken,ServerPort,UserAgent,Referer,ProtocolVersion,Host" | |
| $customFields = @( | |
| @{ name = "X-Forwarded-For"; src = "X-Forwarded-For"; type = "RequestHeader" } | |
| @{ name = "Correlation-ID"; src = "X-Correlation-ID"; type = "RequestHeader" } | |
| @{ name = "TLS-Protocol"; src = "CRYPT_PROTOCOL"; type = "ServerVariable" } | |
| ) | |
| # 1) Baseline at server level | |
| Set-WebConfigurationProperty -PSPath $apphost -Filter "system.applicationHost/sites/siteDefaults/logFile" -Name logExtFileFlags -Value $standardFlags | |
| Clear-WebConfiguration -PSPath $apphost -Filter "system.applicationHost/sites/siteDefaults/logFile/customFields" | |
| foreach ($f in $customFields) { | |
| Add-WebConfigurationProperty -PSPath $apphost -Filter "system.applicationHost/sites/siteDefaults/logFile/customFields" ` | |
| -Name "." -Value @{ logFieldName = $f.name; sourceName = $f.src; sourceType = $f.type } | |
| } | |
| # 2) Normalize each site: same standard flags, and clear per-site customFields so they inherit | |
| foreach ($site in Get-Website) { | |
| $filter = "system.applicationHost/sites/site[@name='$($site.Name)']/logFile" | |
| Set-WebConfigurationProperty -PSPath $apphost -Filter $filter -Name logExtFileFlags -Value $standardFlags | |
| Clear-WebConfiguration -PSPath $apphost -Filter "$filter/customFields" -ErrorAction SilentlyContinue | |
| } | |
| # Expected state (must match what enforcement applied) | |
| $expectedFlags = ($standardFlags -split ',' | ForEach-Object { $_.Trim() } | Sort-Object) | |
| $expectedCustom = $customFields | ForEach-Object { "$($_.name)|$($_.type)|$($_.src)" } | Sort-Object | |
| $results = foreach ($site in Get-Website) { | |
| $filter = "system.applicationHost/sites/site[@name='$($site.Name)']/logFile" | |
| # Effective standard flags (compare as a SET - IIS reorders them) | |
| $actualFlags = (Get-WebConfigurationProperty -PSPath $apphost -Filter $filter -Name logExtFileFlags).ToString() ` | |
| -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ } | Sort-Object | |
| $flagsOk = -not (Compare-Object $expectedFlags $actualFlags) | |
| # Effective custom fields (inherited from siteDefaults + any local) | |
| $cf = Get-WebConfigurationProperty -PSPath $apphost -Filter "$filter/customFields" -Name Collection | |
| $actualCustom = @($cf | ForEach-Object { | |
| "$($_.logFieldName)|$($_.sourceType)|$($_.sourceName)" | |
| } | Sort-Object) | |
| $customOk = -not (Compare-Object $expectedCustom $actualCustom) | |
| # Surface what's wrong, if anything | |
| $missingFlags = (Compare-Object $expectedFlags $actualFlags | | |
| Where-Object SideIndicator -eq '<=').InputObject -join ',' | |
| $extraFlags = (Compare-Object $expectedFlags $actualFlags | | |
| Where-Object SideIndicator -eq '=>').InputObject -join ',' | |
| [pscustomobject]@{ | |
| Site = $site.Name | |
| FlagsOK = $flagsOk | |
| CustomOK = $customOk | |
| Pass = ($flagsOk -and $customOk) | |
| Missing = $missingFlags | |
| Extra = $extraFlags | |
| } | |
| } | |
| Write-Host "`n=== Verification ===" -ForegroundColor Cyan | |
| $results | Format-Table Site, FlagsOK, CustomOK, Pass, Missing, Extra -AutoSize | |
| $failed = $results | Where-Object { -not $_.Pass } | |
| if ($failed) { | |
| Write-Host "`n$($failed.Count) site(s) FAILED validation." -ForegroundColor Red | |
| $failed | ForEach-Object { | |
| Write-Host " [$($_.Site)] flags=$($_.FlagsOK) custom=$($_.CustomOK) missing='$($_.Missing)' extra='$($_.Extra)'" -ForegroundColor Red | |
| } | |
| # exit 1 # uncomment if running as a pipeline task so the step fails loudly | |
| } else { | |
| Write-Host "`nAll $($results.Count) site(s) PASSED - effective logging settings match the standard." -ForegroundColor Green | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment