You want to know which IIS application failed. You open Event Viewer. You find thousands of entries. This script lists your IIS applications. You pick one. The script shows the last 10 errors for that application.
What the Script Does
- It lists all IIS sites and applications with
appcmd list app. - It shows the application pool for each application.
- It scans the Application event log for IIS, ASP.NET Core, and .NET Runtime errors.
- It scans the System event log for HTTP errors (500.x).
- It matches entries by site name, application pool, or application name.
- It shows the last 10 errors. The newest error comes first.
How to Run the Script
- Log on to the IIS server.
- Open PowerShell 5.1 or PowerShell 7.
- Copy the script from this page.
- Paste the script into the console. Press Enter.
- Type the number of the application. Press Enter.
- Type
qto quit.
The script is read-only. You do not need Administrator rights. The script uses appcmd.exe, which exists on every IIS server.
The Script
Copy the whole block. Paste it into PowerShell on the IIS server.
$AppCmd = Join-Path $env:SystemRoot 'system32\inetsrv\appcmd.exe'
if (-not (Test-Path -LiteralPath $AppCmd)) { Write-Host "ERROR: appcmd.exe not found. Run this on the IIS server." -ForegroundColor Red; exit 1 }
$Providers = @(
'IIS AspNetCore Module V2', 'IIS AspNetCore Module', 'ASP.NET', '.NET Runtime',
'Application Error', 'IIS-W3SVC-WP', 'Microsoft-Windows-IIS-W3SVC-WP',
'WAS', 'Windows Process Activation Service'
)
function Get-IisApps {
$apps = @()
foreach ($line in (& $AppCmd list app 2>$null)) {
if ($line -match 'APP\s+"([^"]+)"\s*\(applicationPool:([^)]+)\)') {
$apps += [pscustomobject]@{ Path = $Matches[1]; Pool = $Matches[2] }
}
}
return $apps
}
function Show-ErrorsForApp {
param($App)
$siteName = ($App.Path -split '/')[0]
$leaf = ($App.Path -split '/')[-1]
if (-not $leaf) { $leaf = $siteName }
Write-Host "`n Scanning event logs for '$($App.Path)' (pool: $($App.Pool))..." -ForegroundColor Cyan
$events = @(Get-WinEvent -LogName Application -MaxEvents 3000 -ErrorAction SilentlyContinue |
Where-Object { $Providers -contains $_.ProviderName } |
Where-Object {
$_.Message -match [regex]::Escape($siteName) -or
$_.Message -match [regex]::Escape($App.Pool) -or
$_.Message -match [regex]::Escape($leaf)
})
$http = @(Get-WinEvent -LogName System -ProviderName HttpEvent -MaxEvents 1500 -ErrorAction SilentlyContinue |
Where-Object {
$_.Message -match [regex]::Escape($siteName) -or
$_.Message -match [regex]::Escape($App.Pool) -or
$_.Message -match [regex]::Escape($leaf)
})
$events = @($events + $http | Sort-Object TimeCreated -Descending)
if ($events.Count -eq 0) {
Write-Host " No errors found for '$($App.Path)' in the scanned logs." -ForegroundColor Yellow
Write-Host " (Scanned: latest 3000 Application entries + latest 1500 System HttpEvent entries.)" -ForegroundColor DarkYellow
return
}
$shown = @($events | Select-Object -First 10)
Write-Host " Found $($events.Count) matching error(s). Showing latest $($shown.Count):" -ForegroundColor Cyan
$i = 0
foreach ($e in $shown) {
$i++
$msg = ($e.Message -split "`r?`n" | Where-Object { $_.Trim() -ne '' }) -join ' '
if ($msg.Length -gt 300) { $msg = $msg.Substring(0, 300) + '...' }
Write-Host ""
Write-Host " [$i] $($e.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss')) Log=$($e.LogName) $($e.ProviderName) #$($e.Id) $($e.LevelDisplayName)" -ForegroundColor White
Write-Host " $msg"
}
}
$apps = Get-IisApps
if (-not $apps -or $apps.Count -eq 0) { Write-Host "No IIS applications found." -ForegroundColor Red; exit 1 }
while ($true) {
Clear-Host
Write-Host "================================================" -ForegroundColor Cyan
Write-Host " IIS Application Error Viewer" -ForegroundColor Cyan
Write-Host "================================================" -ForegroundColor Cyan
Write-Host ""
Write-Host " Applications:" -ForegroundColor White
for ($i = 0; $i -lt $apps.Count; $i++) {
Write-Host (" {0,2}. {1} (pool: {2})" -f ($i + 1), $apps[$i].Path, $apps[$i].Pool)
}
Write-Host ""
$pick = Read-Host " Enter number (or q to quit)"
if ($pick -match '^[Qq]$') { exit 0 }
if ($pick -match '^\d+$') {
$n = [int]$pick - 1
if ($n -ge 0 -and $n -lt $apps.Count) { Show-ErrorsForApp -App $apps[$n] }
else { Write-Host " Invalid number." -ForegroundColor Red }
} else {
Write-Host " Enter a number from the list." -ForegroundColor Yellow
}
Read-Host "`n Press Enter to return to the list"
}
How the Script Works
The script calls appcmd list app. This command returns every application with its application pool. The script shows the result as a numbered list.
When you pick an application, the script scans two event logs:
- The Application log. The script reads providers such as IIS AspNetCore Module V2, .NET Runtime, and WAS.
- The System log. The script reads the HttpEvent provider. This provider records HTTP 500 errors.
The script keeps an entry when the message contains the site name, the application pool name, or the application name. Other entries do not appear.
Limits
- The scan reads the latest 3000 entries from the Application log.
- The scan reads the latest 1500 entries from the System log.
- Each message shows a maximum of 300 characters.
- The script matches by name only. It does not match by process ID or site ID.
If the errors are HTTP 500 errors, read Fixing HTTP 500 on ASP.NET Core under IIS. If the errors are 403 errors on static files, read IIS 403 Errors on Static Files After a Deployment.
Summary
- The script lists every IIS application with its application pool.
- You pick one application. The script shows its last 10 errors.
- The script scans the Application log and the System log.
- It matches entries by site name, application pool, or application name.
- No Administrator rights are required.