1. [Quick Setup](#quick-setup)
2. [Discovery & Info Functions](#discovery--info-functions)
3. [Website Monitoring Functions](#website-monitoring-functions)
4. [Restart & Recovery Functions](#restart--recovery-functions)
5. [Performance Monitoring](#performance-monitoring)
6. [Log Monitoring Functions](#log-monitoring-functions)
7. [Health Check Functions](#health-check-functions)
8. [Alerting & Notification Functions](#alerting--notification-functions)
9. [Automated Recovery Functions](#automated-recovery-functions)
10. [Bulk Management Functions](#bulk-management-functions)
11. [Usage Examples](#usage-examples)
---
# Check profile location
$PROFILE
# Edit profile (creates if doesn't exist)
notepad $PROFILE
# Add all functions below to your profile, then reload:
. $PROFILE
# Add to top of profile
Import-Module WebAdministration,IISAdministration -ErrorAction SilentlyContinue
---
function Get-IISSiteInfo {
<#
.SYNOPSIS
Get comprehensive information about IIS sites
.PARAMETER SiteName
Site name or wildcard pattern. Default is all sites.
.EXAMPLE
Get-IISSiteInfo "MyWebsite"
Get-IISSiteInfo "*test*"
#>
param([string]$SiteName = "*")
Get-IISSite | Where-Object {$_.Name -like $SiteName} | ForEach-Object {
$site = $_
$appPool = Get-IISAppPool $site.Applications[0].ApplicationPoolName -ea 0
$bindings = Get-IISSiteBinding $site.Name
$physicalPath = $site.Applications[0].VirtualDirectories[0].PhysicalPath
# Test if site responds
$httpBinding = $bindings | Where-Object {$_.Protocol -eq "http"} | Select-Object -First 1
$siteUrl = if($httpBinding) {
"http://localhost$($httpBinding.BindingInformation.Split(':')[1])"
} else { "N/A" }
$isResponding = $false
if($siteUrl -ne "N/A") {
try {
$response = Invoke-WebRequest $siteUrl -UseBasicParsing -TimeoutSec 5 -ea 0
$isResponding = $response.StatusCode -eq 200
} catch { }
}
[PSCustomObject]@{
SiteName = $site.Name
SiteID = $site.ID
SiteState = $site.State
PhysicalPath = $physicalPath
PathExists = (Test-Path $physicalPath)
AppPoolName = $appPool.Name
AppPoolState = if($appPool){$appPool.State}else{"Unknown"}
DotNetVersion = if($appPool){$appPool.ManagedRuntimeVersion}else{"Unknown"}
Bindings = ($bindings | ForEach-Object {"$($_.Protocol):$($_.BindingInformation)"}) -join ", "
SSL = ($bindings | Where-Object {$_.Protocol -eq "https"}).Count -gt 0
IsResponding = $isResponding
TestUrl = $siteUrl
}
} | Format-Table -AutoSize
}
function Get-SiteStatus {
<#
.SYNOPSIS
Quick status check for specific site
.PARAMETER SiteName
Name of the site to check
#>
param(
[Parameter(Mandatory=$true)]
[string]$SiteName
)
try {
$site = Get-IISSite $SiteName -ea Stop
$appPool = Get-IISAppPool $site.Applications[0].ApplicationPoolName
$physicalPath = $site.Applications[0].VirtualDirectories[0].PhysicalPath
# Get worker process info
$workerProcess = Get-WmiObject -Query "SELECT * FROM Win32_Process WHERE Name='w3wp.exe' AND CommandLine LIKE '%$($appPool.Name)%'" -ea 0
Write-Host "=== Site Status: $SiteName ===" -ForegroundColor Cyan
Write-Host "Site State: $($site.State)" -ForegroundColor $(if($site.State -eq "Started"){"Green"}else{"Red"})
Write-Host "App Pool: $($appPool.Name) - $($appPool.State)" -ForegroundColor $(if($appPool.State -eq "Started"){"Green"}else{"Red"})
Write-Host "Physical Path: $physicalPath" -ForegroundColor White
Write-Host "Path Exists: $(Test-Path $physicalPath)" -ForegroundColor $(if(Test-Path $physicalPath){"Green"}else{"Red"})
if($workerProcess) {
Write-Host "Worker Process: PID $($workerProcess.ProcessId) - Memory: $([math]::Round($workerProcess.WorkingSetSize/1MB,2))MB" -ForegroundColor Green
} else {
Write-Host "Worker Process: Not Running" -ForegroundColor Yellow
}
# Test HTTP response
$binding = Get-IISSiteBinding $SiteName | Where-Object {$_.Protocol -eq "http"} | Select-Object -First 1
if($binding) {
$testUrl = "http://localhost$($binding.BindingInformation.Split(':')[1])"
try {
$response = Invoke-WebRequest $testUrl -UseBasicParsing -TimeoutSec 5
Write-Host "HTTP Test: $($response.StatusCode) - $($response.StatusDescription)" -ForegroundColor Green
} catch {
Write-Host "HTTP Test: Failed - $($_.Exception.Message)" -ForegroundColor Red
}
}
} catch {
Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red
}
}
---
function Watch-IISSite {
<#
.SYNOPSIS
Continuously monitor a website with real-time status updates
.PARAMETER SiteName
Name of the site to monitor
.PARAMETER IntervalSeconds
Check interval in seconds (default: 30)
.PARAMETER AlertThreshold
Number of consecutive failures before alert (default: 3)
#>
param(
[Parameter(Mandatory=$true)]
[string]$SiteName,
[int]$IntervalSeconds = 30,
[int]$AlertThreshold = 3,
[switch]$AutoRestart
)
$failureCount = 0
$startTime = Get-Date
$checkCount = 0
Write-Host "Starting monitor for: $SiteName" -ForegroundColor Green
Write-Host "Check interval: $IntervalSeconds seconds" -ForegroundColor White
Write-Host "Alert threshold: $AlertThreshold failures" -ForegroundColor White
Write-Host "Auto-restart: $($AutoRestart.IsPresent)" -ForegroundColor White
Write-Host "Press Ctrl+C to stop monitoring" -ForegroundColor Yellow
Write-Host ""
try {
while($true) {
$checkCount++
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
# Check site status
$site = Get-IISSite $SiteName -ea 0
$appPool = if($site) { Get-IISAppPool $site.Applications[0].ApplicationPoolName -ea 0 } else { $null }
$siteOk = $site -and $site.State -eq "Started"
$poolOk = $appPool -and $appPool.State -eq "Started"
# Test HTTP response
$httpOk = $false
$responseTime = 0
if($siteOk) {
$binding = Get-IISSiteBinding $SiteName | Where-Object {$_.Protocol -eq "http"} | Select-Object -First 1
if($binding) {
$testUrl = "http://localhost$($binding.BindingInformation.Split(':')[1])"
try {
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$response = Invoke-WebRequest $testUrl -UseBasicParsing -TimeoutSec 10
$stopwatch.Stop()
$responseTime = $stopwatch.ElapsedMilliseconds
$httpOk = $response.StatusCode -eq 200
} catch {
$httpOk = $false
}
}
}
$allOk = $siteOk -and $poolOk -and $httpOk
if($allOk) {
$failureCount = 0
$status = "✓ OK"
$color = "Green"
} else {
$failureCount++
$status = "✗ FAILED"
$color = "Red"
}
# Display status
$uptimeSpan = (Get-Date) - $startTime
$uptime = "{0:hh\:mm\:ss}" -f $uptimeSpan
Write-Host "$timestamp | Check #$checkCount | $status | Site:$siteOk Pool:$poolOk HTTP:$httpOk | Response:${responseTime}ms | Failures:$failureCount | Uptime:$uptime" -ForegroundColor $color
# Alert and auto-restart logic
if($failureCount -ge $AlertThreshold) {
Write-Host "ALERT: $AlertThreshold consecutive failures detected!" -ForegroundColor Red -BackgroundColor White
if($AutoRestart.IsPresent) {
Write-Host "Attempting auto-restart..." -ForegroundColor Yellow
try {
Restart-IISSiteComplete $SiteName -Force
Write-Host "Auto-restart completed" -ForegroundColor Green
$failureCount = 0
} catch {
Write-Host "Auto-restart failed: $($_.Exception.Message)" -ForegroundColor Red
}
}
}
Start-Sleep $IntervalSeconds
}
} catch [System.Management.Automation.PipelineStoppedException] {
Write-Host "`nMonitoring stopped by user" -ForegroundColor Yellow
}
}
function Get-SitePerformance {
<#
.SYNOPSIS
Get real-time performance metrics for a site
.PARAMETER SiteName
Name of the site to monitor
.PARAMETER Samples
Number of samples to collect (default: 5)
#>
param(
[Parameter(Mandatory=$true)]
[string]$SiteName,
[int]$Samples = 5
)
$site = Get-IISSite $SiteName -ea Stop
$appPoolName = $site.Applications[0].ApplicationPoolName
Write-Host "Collecting $Samples performance samples for: $SiteName" -ForegroundColor Green
$results = @()
for($i = 1; $i -le $Samples; $i++) {
Write-Progress -Activity "Collecting Performance Data" -Status "Sample $i of $Samples" -PercentComplete (($i / $Samples) * 100)
$timestamp = Get-Date
# Get performance counters
try {
$currentConnections = (Get-Counter "\Web Service($SiteName)\Current Connections" -SampleInterval 1 -MaxSamples 1).CounterSamples[0].CookedValue
} catch { $currentConnections = "N/A" }
try {
$requestsPerSec = (Get-Counter "\Web Service($SiteName)\Requests/Sec" -SampleInterval 1 -MaxSamples 1).CounterSamples[0].CookedValue
} catch { $requestsPerSec = "N/A" }
try {
$queueLength = (Get-Counter "\HTTP Service Request Queues($appPoolName)\CurrentQueueSize" -SampleInterval 1 -MaxSamples 1).CounterSamples[0].CookedValue
} catch { $queueLength = "N/A" }
# Get worker process info
$workerProcess = Get-WmiObject -Query "SELECT * FROM Win32_Process WHERE Name='w3wp.exe' AND CommandLine LIKE '%$appPoolName%'" -ea 0
$cpuPercent = if($workerProcess) {
try { (Get-Counter "\Process(w3wp*)\% Processor Time" -SampleInterval 1 -MaxSamples 1).CounterSamples[0].CookedValue } catch { "N/A" }
} else { 0 }
$memoryMB = if($workerProcess) { [math]::Round($workerProcess.WorkingSetSize/1MB,2) } else { 0 }
$results += [PSCustomObject]@{
Time = $timestamp.ToString("HH:mm:ss")
CurrentConnections = $currentConnections
RequestsPerSec = $requestsPerSec
QueueLength = $queueLength
CPUPercent = $cpuPercent
MemoryMB = $memoryMB
}
if($i -lt $Samples) { Start-Sleep 2 }
}
Write-Progress -Activity "Collecting Performance Data" -Completed
Write-Host "`nPerformance Summary for: $SiteName" -ForegroundColor Cyan
$results | Format-Table -AutoSize
# Calculate averages
$avgConnections = ($results | Where-Object {$_.CurrentConnections -ne "N/A"} | Measure-Object -Property CurrentConnections -Average).Average
$avgRequests = ($results | Where-Object {$_.RequestsPerSec -ne "N/A"} | Measure-Object -Property RequestsPerSec -Average).Average
$avgMemory = ($results | Measure-Object -Property MemoryMB -Average).Average
Write-Host "Averages:" -ForegroundColor Yellow
Write-Host " Connections: $([math]::Round($avgConnections,2))" -ForegroundColor White
Write-Host " Requests/Sec: $([math]::Round($avgRequests,2))" -ForegroundColor White
Write-Host " Memory (MB): $([math]::Round($avgMemory,2))" -ForegroundColor White
}
---
function Restart-IISSiteComplete {
<#
.SYNOPSIS
Restart IIS site and its application pool with validation
.PARAMETER SiteName
Name of the site to restart
.PARAMETER RestartAppPool
Whether to restart the application pool (default: true)
.PARAMETER WaitSeconds
Seconds to wait between stop/start (default: 3)
.PARAMETER Force
Skip confirmation prompts
#>
param(
[Parameter(Mandatory=$true)]
[string]$SiteName,
[bool]$RestartAppPool = $true,
[int]$WaitSeconds = 3,
[switch]$Force
)
if(!$Force) {
$confirm = Read-Host "Restart site '$SiteName'$(if($RestartAppPool){' and app pool'})? (y/N)"
if($confirm -ne 'y') {
Write-Host "Operation cancelled" -ForegroundColor Yellow
return
}
}
try {
$site = Get-IISSite $SiteName -ErrorAction Stop
$appPoolName = $site.Applications[0].ApplicationPoolName
Write-Host "Starting restart sequence for: $SiteName" -ForegroundColor Cyan
# Stop site
Write-Host " Stopping site..." -ForegroundColor Yellow
Stop-IISSite $SiteName
Write-Host " Site stopped" -ForegroundColor Green
if($RestartAppPool) {
# Restart app pool
Write-Host " Restarting application pool: $appPoolName..." -ForegroundColor Yellow
Restart-WebAppPool $appPoolName
Write-Host " App pool restarted" -ForegroundColor Green
}
# Wait
if($WaitSeconds -gt 0) {
Write-Host " Waiting $WaitSeconds seconds..." -ForegroundColor White
Start-Sleep $WaitSeconds
}
# Start site
Write-Host " Starting site..." -ForegroundColor Yellow
Start-IISSite $SiteName
Write-Host " Site started" -ForegroundColor Green
# Verify restart
Start-Sleep 2
$siteStatus = (Get-IISSite $SiteName).State
$poolStatus = (Get-IISAppPool $appPoolName).State
if($siteStatus -eq "Started" -and $poolStatus -eq "Started") {
Write-Host "✓ Restart completed successfully" -ForegroundColor Green
# Test HTTP response
$binding = Get-IISSiteBinding $SiteName | Where-Object {$_.Protocol -eq "http"} | Select-Object -First 1
if($binding) {
$testUrl = "http://localhost$($binding.BindingInformation.Split(':')[1])"
try {
Start-Sleep 3 # Give site time to initialize
$response = Invoke-WebRequest $testUrl -UseBasicParsing -TimeoutSec 10
Write-Host "✓ HTTP test successful: $($response.StatusCode)" -ForegroundColor Green
} catch {
Write-Host "⚠ HTTP test failed: $($_.Exception.Message)" -ForegroundColor Yellow
}
}
} else {
Write-Host "✗ Restart verification failed - Site: $siteStatus, Pool: $poolStatus" -ForegroundColor Red
}
} catch {
Write-Host "✗ Restart failed: $($_.Exception.Message)" -ForegroundColor Red
throw
}
}
function Restart-AppPoolOnly {
<#
.SYNOPSIS
Restart only the application pool without touching the site
.PARAMETER SiteName
Site name to identify the app pool
.PARAMETER AppPoolName
Or specify app pool name directly
#>
param(
[string]$SiteName,
[string]$AppPoolName
)
if($SiteName) {
$site = Get-IISSite $SiteName -ErrorAction Stop
$AppPoolName = $site.Applications[0].ApplicationPoolName
}
if(!$AppPoolName) {
throw "Must specify either SiteName or AppPoolName"
}
Write-Host "Restarting application pool: $AppPoolName" -ForegroundColor Cyan
try {
$oldState = (Get-IISAppPool $AppPoolName).State
Write-Host " Current state: $oldState" -ForegroundColor White
Restart-WebAppPool $AppPoolName
Start-Sleep 2
$newState = (Get-IISAppPool $AppPoolName).State
Write-Host " New state: $newState" -ForegroundColor Green
# Check for worker process
Start-Sleep 3
$workerProcess = Get-WmiObject -Query "SELECT * FROM Win32_Process WHERE Name='w3wp.exe' AND CommandLine LIKE '%$AppPoolName%'" -ea 0
if($workerProcess) {
Write-Host "✓ Worker process started: PID $($workerProcess.ProcessId)" -ForegroundColor Green
} else {
Write-Host "⚠ No worker process detected yet" -ForegroundColor Yellow
}
} catch {
Write-Host "✗ App pool restart failed: $($_.Exception.Message)" -ForegroundColor Red
throw
}
}
function Invoke-SiteRecovery {
<#
.SYNOPSIS
Intelligent site recovery with progressive escalation
.PARAMETER SiteName
Name of the site to recover
.PARAMETER TestUrl
Optional custom URL to test (default: auto-detect)
#>
param(
[Parameter(Mandatory=$true)]
[string]$SiteName,
[string]$TestUrl
)
Write-Host "Starting recovery process for: $SiteName" -ForegroundColor Cyan
# Get site info
$site = Get-IISSite $SiteName -ErrorAction Stop
$appPoolName = $site.Applications[0].ApplicationPoolName
# Auto-detect test URL if not provided
if(!$TestUrl) {
$binding = Get-IISSiteBinding $SiteName | Where-Object {$_.Protocol -eq "http"} | Select-Object -First 1
if($binding) {
$TestUrl = "http://localhost$($binding.BindingInformation.Split(':')[1])"
}
}
# Test function
function Test-SiteResponse {
if(!$TestUrl) { return $true } # Skip if no URL
try {
$response = Invoke-WebRequest $TestUrl -UseBasicParsing -TimeoutSec 10
return $response.StatusCode -eq 200
} catch {
return $false
}
}
# Recovery steps with progressive escalation
$steps = @(
@{ Name = "Reset App Pool Failures"; Action = { Reset-WebAppPool $appPoolName } },
@{ Name = "Start App Pool"; Action = { Start-WebAppPool $appPoolName } },
@{ Name = "Start Site"; Action = { Start-IISSite $SiteName } },
@{ Name = "Recycle App Pool"; Action = { Restart-WebAppPool $appPoolName } },
@{ Name = "Full Restart"; Action = { Restart-IISSiteComplete $SiteName -Force } }
)
foreach($step in $steps) {
Write-Host " Attempting: $($step.Name)..." -ForegroundColor Yellow
try {
& $step.Action
Start-Sleep 5 # Give time for changes to take effect
if(Test-SiteResponse) {
Write-Host "✓ Recovery successful with: $($step.Name)" -ForegroundColor Green
# Final verification
$siteState = (Get-IISSite $SiteName).State
$poolState = (Get-IISAppPool $appPoolName).State
Write-Host " Final status - Site: $siteState, Pool: $poolState" -ForegroundColor White
return $true
}
} catch {
Write-Host " Failed: $($_.Exception.Message)" -ForegroundColor Red
}
}
Write-Host "✗ All recovery attempts failed" -ForegroundColor Red
return $false
}
---
function Show-SitePerformanceDashboard {
<#
.SYNOPSIS
Real-time performance dashboard for a site
.PARAMETER SiteName
Name of the site to monitor
.PARAMETER RefreshSeconds
Dashboard refresh interval (default: 5)
#>
param(
[Parameter(Mandatory=$true)]
[string]$SiteName,
[int]$RefreshSeconds = 5
)
$site = Get-IISSite $SiteName -ErrorAction Stop
$appPoolName = $site.Applications[0].ApplicationPoolName
Write-Host "Starting performance dashboard for: $SiteName" -ForegroundColor Green
Write-Host "Press Ctrl+C to stop" -ForegroundColor Yellow
try {
while($true) {
Clear-Host
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Write-Host "╔══════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
Write-Host "║ IIS PERFORMANCE DASHBOARD ║" -ForegroundColor Cyan
Write-Host "╠══════════════════════════════════════════════════════════════╣" -ForegroundColor Cyan
Write-Host "║ Site: $($SiteName.PadRight(50)) ║" -ForegroundColor Cyan
Write-Host "║ Time: $($timestamp.PadRight(50)) ║" -ForegroundColor Cyan
Write-Host "╚══════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan
# Site & App Pool Status
$siteState = (Get-IISSite $SiteName).State
$poolState = (Get-IISAppPool $appPoolName).State
Write-Host "`nSTATUS:" -ForegroundColor Yellow
Write-Host " Site State: $siteState" -ForegroundColor $(if($siteState -eq "Started"){"Green"}else{"Red"})
Write-Host " Pool State: $poolState" -ForegroundColor $(if($poolState -eq "Started"){"Green"}else{"Red"})
# Performance Counters
Write-Host "`nPERFORMANCE:" -ForegroundColor Yellow
try {
$connections = (Get-Counter "\Web Service($SiteName)\Current Connections" -SampleInterval 1 -MaxSamples 1).CounterSamples[0].CookedValue
Write-Host " Current Connections: $connections" -ForegroundColor White
} catch {
Write-Host " Current Connections: N/A" -ForegroundColor Gray
}
try {
$requests = (Get-Counter "\Web Service($SiteName)\Requests/Sec" -SampleInterval 1 -MaxSamples 1).CounterSamples[0].CookedValue
Write-Host " Requests/Second: $([math]::Round($requests,2))" -ForegroundColor White
} catch {
Write-Host " Requests/Second: N/A" -ForegroundColor Gray
}
try {
$queue = (Get-Counter "\HTTP Service Request Queues($appPoolName)\CurrentQueueSize" -SampleInterval 1 -MaxSamples 1).CounterSamples[0].CookedValue
Write-Host " Request Queue: $queue" -ForegroundColor $(if($queue -gt 0){"Yellow"}else{"Green"})
} catch {
Write-Host " Request Queue: N/A" -ForegroundColor Gray
}
# Worker Process Info
$workerProcess = Get-WmiObject -Query "SELECT * FROM Win32_Process WHERE Name='w3wp.exe' AND CommandLine LIKE '%$appPoolName%'" -ea 0
Write-Host "`nWORKER PROCESS:" -ForegroundColor Yellow
if($workerProcess) {
$memoryMB = [math]::Round($workerProcess.WorkingSetSize/1MB,2)
$startTime = $workerProcess.ConvertToDateTime($workerProcess.CreationDate)
$uptime = (Get-Date) - $startTime
Write-Host " Process ID: $($workerProcess.ProcessId)" -ForegroundColor White
Write-Host " Memory Usage: ${memoryMB} MB" -ForegroundColor $(if($memoryMB -gt 500){"Yellow"}elseif($memoryMB -gt 1000){"Red"}else{"Green"})
Write-Host " Uptime: $($uptime.Days)d $($uptime.Hours)h $($uptime.Minutes)m" -ForegroundColor White
try {
$cpu = (Get-Counter "\Process(w3wp*)\% Processor Time" -SampleInterval 1 -MaxSamples 1).CounterSamples[0].CookedValue
Write-Host " CPU Usage: $([math]::Round($cpu,1))%" -ForegroundColor $(if($cpu -gt 80){"Red"}elseif($cpu -gt 50){"Yellow"}else{"Green"})
} catch {
Write-Host " CPU Usage: N/A" -ForegroundColor Gray
}
} else {
Write-Host " No worker process running" -ForegroundColor Red
}
# HTTP Test
Write-Host "`nHTTP TEST:" -ForegroundColor Yellow
$binding = Get-IISSiteBinding $SiteName | Where-Object {$_.Protocol -eq "http"} | Select-Object -First 1
if($binding) {
$testUrl = "http://localhost$($binding.BindingInformation.Split(':')[1])"
try {
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$response = Invoke-WebRequest $testUrl -UseBasicParsing -TimeoutSec 5
$stopwatch.Stop()
$responseTime = $stopwatch.ElapsedMilliseconds
Write-Host " Status: $($response.StatusCode) - $($response.StatusDescription)" -ForegroundColor Green
Write-Host " Response Time: ${responseTime}ms" -ForegroundColor $(if($responseTime -gt 5000){"Red"}elseif($responseTime -gt 1000){"Yellow"}else{"Green"})
} catch {
Write-Host " Status: Failed - $($_.Exception.Message)" -ForegroundColor Red
}
} else {
Write-Host " No HTTP binding found" -ForegroundColor Gray
}
Write-Host "`nRefreshing in $RefreshSeconds seconds..." -ForegroundColor Gray
Start-Sleep $RefreshSeconds
}
} catch [System.Management.Automation.PipelineStoppedException] {
Write-Host "`nDashboard stopped" -ForegroundColor Yellow
}
}
---
function Watch-IISLogs {
<#
.SYNOPSIS
Monitor IIS logs in real-time for a specific site
.PARAMETER SiteName
Name of the site to monitor
.PARAMETER ErrorsOnly
Show only error entries (4xx, 5xx)
.PARAMETER Follow
Continuously follow the log file
#>
param(
[Parameter(Mandatory=$true)]
[string]$SiteName,
[switch]$ErrorsOnly,
[switch]$Follow
)
$site = Get-IISSite $SiteName -ErrorAction Stop
$siteId = $site.ID
$logPath = "C:\inetpub\logs\LogFiles\W3SVC$siteId"
if(!(Test-Path $logPath)) {
throw "Log directory not found: $logPath"
}
Write-Host "Monitoring logs for: $SiteName (Site ID: $siteId)" -ForegroundColor Green
Write-Host "Log path: $logPath" -ForegroundColor White
Write-Host "Errors only: $($ErrorsOnly.IsPresent)" -ForegroundColor White
Write-Host "Follow mode: $($Follow.IsPresent)" -ForegroundColor White
Write-Host ""
if($Follow) {
$latestLog = Get-ChildItem $logPath -Filter "*.log" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
$initialPosition = $latestLog.Length
Write-Host "Following: $($latestLog.Name)" -ForegroundColor Cyan
Write-Host "Press Ctrl+C to stop" -ForegroundColor Yellow
Write-Host ""
try {
while($true) {
$currentLog = Get-ChildItem $logPath -Filter "*.log" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
# Check if log file changed
if($currentLog.Name -ne $latestLog.Name) {
Write-Host "New log file: $($currentLog.Name)" -ForegroundColor Yellow
$latestLog = $currentLog
$initialPosition = 0
}
# Read new content
if($currentLog.Length -gt $initialPosition) {
$stream = [System.IO.FileStream]::new($currentLog.FullName, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
$stream.Seek($initialPosition, [System.IO.SeekOrigin]::Begin) | Out-Null
$reader = [System.IO.StreamReader]::new($stream)
while(($line = $reader.ReadLine()) -ne $null) {
if($line -notlike "#*") { # Skip comments
$fields = $line -split " "
if($fields.Count -ge 9) {
$timestamp = "$($fields[0]) $($fields[1])"
$clientIP = $fields[2]
$method = $fields[3]
$uriStem = $fields[4]
$statusCode = $fields[8]
$isError = $statusCode -match "^[45]\d\d$"
if(!$ErrorsOnly -or $isError) {
$color = if($isError) {"Red"} elseif($statusCode -eq "200") {"Green"} else {"White"}
Write-Host "$timestamp | $clientIP | $method $uriStem | $statusCode" -ForegroundColor $color
}
}
}
}
$initialPosition = $stream.Position
$reader.Close()
$stream.Close()
}
Start-Sleep 1
}
} catch [System.Management.Automation.PipelineStoppedException] {
Write-Host "`nLog monitoring stopped" -ForegroundColor Yellow
}
} else {
# Show recent entries
$latestLog = Get-ChildItem $logPath -Filter "*.log" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
Write-Host "Showing recent entries from: $($latestLog.Name)" -ForegroundColor Cyan
$lines = Get-Content $latestLog.FullName | Where-Object {$_ -notlike "#*"} | Select-Object -Last 50
foreach($line in $lines) {
$fields = $line -split " "
if($fields.Count -ge 9) {
$statusCode = $fields[8]
$isError = $statusCode -match "^[45]\d\d$"
if(!$ErrorsOnly -or $isError) {
$color = if($isError) {"Red"} elseif($statusCode -eq "200") {"Green"} else {"White"}
Write-Host $line -ForegroundColor $color
}
}
}
}
}
---
function Test-IISSiteHealth {
<#
.SYNOPSIS
Comprehensive health check for IIS site
.PARAMETER SiteName
Name of the site to check
.PARAMETER IncludePerformance
Include performance metrics in health check
#>
param(
[Parameter(Mandatory=$true)]
[string]$SiteName,
[switch]$IncludePerformance
)
$results = [PSCustomObject]@{
SiteName = $SiteName
OverallHealth = "Unknown"
Checks = @()
Warnings = @()
Errors = @()
Recommendations = @()
}
function Add-HealthCheck {
param($Name, $Status, $Details, $Type = "Info")
$results.Checks += [PSCustomObject]@{
Name = $Name
Status = $Status
Details = $Details
Type = $Type
}
if($Type -eq "Error") { $results.Errors += "$Name`: $Details" }
if($Type -eq "Warning") { $results.Warnings += "$Name`: $Details" }
}
Write-Host "Running health check for: $SiteName" -ForegroundColor Green
# 1. Site Existence
try {
$site = Get-IISSite $SiteName -ErrorAction Stop
Add-HealthCheck "Site Exists" "✓ Pass" "Site found with ID $($site.ID)" "Info"
} catch {
Add-HealthCheck "Site Exists" "✗ Fail" "Site not found" "Error"
$results.OverallHealth = "Critical"
return $results
}
# 2. Site State
if($site.State -eq "Started") {
Add-HealthCheck "Site State" "✓ Pass" "Site is started" "Info"
} else {
Add-HealthCheck "Site State" "✗ Fail" "Site state: $($site.State)" "Error"
}
# 3. Application Pool
$appPoolName = $site.Applications[0].ApplicationPoolName
$appPool = Get-IISAppPool $appPoolName -ErrorAction SilentlyContinue
if($appPool) {
if($appPool.State -eq "Started") {
Add-HealthCheck "App Pool State" "✓ Pass" "$appPoolName is started" "Info"
} else {
Add-HealthCheck "App Pool State" "✗ Fail" "$appPoolName state: $($appPool.State)" "Error"
}
# Check rapid-fail protection
if($appPool.Failure.RapidFailProtection) {
$maxCrashes = $appPool.Failure.RapidFailProtectionMaxCrashes
if($maxCrashes -eq 0) {
Add-HealthCheck "Rapid-Fail Protection" "✓ Pass" "No recent failures" "Info"
} else {
Add-HealthCheck "Rapid-Fail Protection" "⚠ Warning" "$maxCrashes recent failures detected" "Warning"
$results.Recommendations += "Check application logs for crash causes"
}
}
} else {
Add-HealthCheck "App Pool" "✗ Fail" "App pool $appPoolName not found" "Error"
}
# 4. Physical Path
$physicalPath = $site.Applications[0].VirtualDirectories[0].PhysicalPath
if(Test-Path $physicalPath) {
Add-HealthCheck "Physical Path" "✓ Pass" "Path exists: $physicalPath" "Info"
# Check for web.config
$webConfig = Join-Path $physicalPath "web.config"
if(Test-Path $webConfig) {
try {
[xml]$config = Get-Content $webConfig
Add-HealthCheck "Web.config" "✓ Pass" "Configuration file is valid XML" "Info"
} catch {
Add-HealthCheck "Web.config" "✗ Fail" "Configuration file has XML errors" "Error"
}
} else {
Add-HealthCheck "Web.config" "⚠ Warning" "No web.config found" "Warning"
}
} else {
Add-HealthCheck "Physical Path" "✗ Fail" "Path does not exist: $physicalPath" "Error"
}
# 5. Bindings and Connectivity
$bindings = Get-IISSiteBinding $SiteName
if($bindings) {
Add-HealthCheck "Site Bindings" "✓ Pass" "$($bindings.Count) binding(s) configured" "Info"
# Test HTTP connectivity
$httpBinding = $bindings | Where-Object {$_.Protocol -eq "http"} | Select-Object -First 1
if($httpBinding) {
$testUrl = "http://localhost$($httpBinding.BindingInformation.Split(':')[1])"
try {
$response = Invoke-WebRequest $testUrl -UseBasicParsing -TimeoutSec 10
Add-HealthCheck "HTTP Connectivity" "✓ Pass" "HTTP $($response.StatusCode) - $($response.StatusDescription)" "Info"
} catch {
Add-HealthCheck "HTTP Connectivity" "✗ Fail" $_.Exception.Message "Error"
}
}
# Check HTTPS if configured
$httpsBinding = $bindings | Where-Object {$_.Protocol -eq "https"} | Select-Object -First 1
if($httpsBinding) {
# Check SSL certificate
try {
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Thumbprint -eq $httpsBinding.certificateHash}
if($cert) {
$daysUntilExpiry = ($cert.NotAfter - (Get-Date)).Days
if($daysUntilExpiry -gt 30) {
Add-HealthCheck "SSL Certificate" "✓ Pass" "Certificate valid for $daysUntilExpiry days" "Info"
} elseif($daysUntilExpiry -gt 0) {
Add-HealthCheck "SSL Certificate" "⚠ Warning" "Certificate expires in $daysUntilExpiry days" "Warning"
$results.Recommendations += "Renew SSL certificate soon"
} else {
Add-HealthCheck "SSL Certificate" "✗ Fail" "Certificate expired $([math]::Abs($daysUntilExpiry)) days ago" "Error"
}
} else {
Add-HealthCheck "SSL Certificate" "✗ Fail" "Certificate not found in store" "Error"
}
} catch {
Add-HealthCheck "SSL Certificate" "⚠ Warning" "Could not verify certificate" "Warning"
}
}
} else {
Add-HealthCheck "Site Bindings" "✗ Fail" "No bindings configured" "Error"
}
# 6. Worker Process
$workerProcess = Get-WmiObject -Query "SELECT * FROM Win32_Process WHERE Name='w3wp.exe' AND CommandLine LIKE '%$appPoolName%'" -ea 0
if($workerProcess) {
$memoryMB = [math]::Round($workerProcess.WorkingSetSize/1MB,2)
if($memoryMB -lt 1000) {
Add-HealthCheck "Worker Process Memory" "✓ Pass" "${memoryMB}MB memory usage" "Info"
} elseif($memoryMB -lt 2000) {
Add-HealthCheck "Worker Process Memory" "⚠ Warning" "${memoryMB}MB memory usage (high)" "Warning"
$results.Recommendations += "Monitor memory usage - consider app pool recycling"
} else {
Add-HealthCheck "Worker Process Memory" "✗ Fail" "${memoryMB}MB memory usage (very high)" "Error"
$results.Recommendations += "Investigate memory leaks or increase recycling frequency"
}
} else {
if($site.State -eq "Started" -and $appPool.State -eq "Started") {
Add-HealthCheck "Worker Process" "⚠ Warning" "No worker process found but site/pool are started" "Warning"
}
}
# 7. Performance Checks (if requested)
if($IncludePerformance) {
try {
$connections = (Get-Counter "\Web Service($SiteName)\Current Connections" -SampleInterval 1 -MaxSamples 1).CounterSamples[0].CookedValue
if($connections -lt 100) {
Add-HealthCheck "Current Connections" "✓ Pass" "$connections active connections" "Info"
} elseif($connections -lt 500) {
Add-HealthCheck "Current Connections" "⚠ Warning" "$connections active connections (moderate load)" "Warning"
} else {
Add-HealthCheck "Current Connections" "✗ Fail" "$connections active connections (high load)" "Error"
}
} catch {
Add-HealthCheck "Current Connections" "⚠ Warning" "Performance counter not available" "Warning"
}
try {
$queueLength = (Get-Counter "\HTTP Service Request Queues($appPoolName)\CurrentQueueSize" -SampleInterval 1 -MaxSamples 1).CounterSamples[0].CookedValue
if($queueLength -eq 0) {
Add-HealthCheck "Request Queue" "✓ Pass" "No requests queued" "Info"
} elseif($queueLength -lt 10) {
Add-HealthCheck "Request Queue" "⚠ Warning" "$queueLength requests queued" "Warning"
} else {
Add-HealthCheck "Request Queue" "✗ Fail" "$queueLength requests queued (bottleneck detected)" "Error"
$results.Recommendations += "Investigate performance bottlenecks or increase worker processes"
}
} catch {
Add-HealthCheck "Request Queue" "⚠ Warning" "Performance counter not available" "Warning"
}
}
# Determine overall health
if($results.Errors.Count -gt 0) {
$results.OverallHealth = "Critical"
} elseif($results.Warnings.Count -gt 0) {
$results.OverallHealth = "Warning"
} else {
$results.OverallHealth = "Healthy"
}
# Display results
Write-Host "`n=== HEALTH CHECK RESULTS ===" -ForegroundColor Cyan
Write-Host "Site: $SiteName" -ForegroundColor White
Write-Host "Overall Health: $($results.OverallHealth)" -ForegroundColor $(switch($results.OverallHealth){"Healthy"{"Green"} "Warning"{"Yellow"} "Critical"{"Red"}})
Write-Host "`nCHECKS:" -ForegroundColor Yellow
$results.Checks | ForEach-Object {
$color = switch($_.Type) {"Info"{"White"} "Warning"{"Yellow"} "Error"{"Red"}}
Write-Host " $($_.Name): $($_.Status) - $($_.Details)" -ForegroundColor $color
}
if($results.Warnings.Count -gt 0) {
Write-Host "`nWARNINGS:" -ForegroundColor Yellow
$results.Warnings | ForEach-Object { Write-Host " $_" -ForegroundColor Yellow }
}
if($results.Errors.Count -gt 0) {
Write-Host "`nERRORS:" -ForegroundColor Red
$results.Errors | ForEach-Object { Write-Host " $_" -ForegroundColor Red }
}
if($results.Recommendations.Count -gt 0) {
Write-Host "`nRECOMMENDATIONS:" -ForegroundColor Cyan
$results.Recommendations | ForEach-Object { Write-Host " $_" -ForegroundColor Cyan }
}
return $results
}
---
function Send-IISAlert {
<#
.SYNOPSIS
Send email alert for IIS issues
.PARAMETER SiteName
Name of the affected site
.PARAMETER AlertType
Type of alert (Error, Warning, Info)
.PARAMETER Message
Alert message
.PARAMETER SmtpServer
SMTP server address
.PARAMETER To
Recipient email addresses
.PARAMETER From
Sender email address
#>
param(
[Parameter(Mandatory=$true)]
[string]$SiteName,
[ValidateSet("Error","Warning","Info")]
[string]$AlertType = "Error",
[Parameter(Mandatory=$true)]
[string]$Message,
[string]$SmtpServer = "localhost",
[string[]]$To = @("admin@company.com"),
[string]$From = "iis-monitor@$($env:COMPUTERNAME).company.com"
)
$subject = "IIS Alert [$AlertType] - $SiteName on $env:COMPUTERNAME"
$priority = switch($AlertType) {
"Error" { "High" }
"Warning" { "Normal" }
"Info" { "Low" }
}
$body = @"
IIS Alert Report
================
Server: $env:COMPUTERNAME
Site: $SiteName
Alert Type: $AlertType
Timestamp: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
Message:
$Message
Site Status:
$(try { Get-SiteStatus $SiteName | Out-String } catch { "Could not retrieve site status" })
--
This is an automated message from IIS Monitor
"@
try {
Send-MailMessage -SmtpServer $SmtpServer -To $To -From $From -Subject $subject -Body $body -Priority $priority
Write-Host "Alert sent successfully" -ForegroundColor Green
} catch {
Write-Host "Failed to send alert: $($_.Exception.Message)" -ForegroundColor Red
}
}
---
function Start-IISAutoRecovery {
<#
.SYNOPSIS
Start automated recovery service for critical sites
.PARAMETER SiteNames
Array of site names to monitor
.PARAMETER CheckInterval
Check interval in seconds (default: 60)
.PARAMETER MaxRestartAttempts
Maximum restart attempts before giving up (default: 3)
#>
param(
[Parameter(Mandatory=$true)]
[string[]]$SiteNames,
[int]$CheckInterval = 60,
[int]$MaxRestartAttempts = 3
)
$recoveryState = @{}
foreach($site in $SiteNames) {
$recoveryState[$site] = @{
FailureCount = 0
LastRestart = $null
RestartAttempts = 0
}
}
Write-Host "Starting auto-recovery service for sites: $($SiteNames -join ', ')" -ForegroundColor Green
Write-Host "Check interval: $CheckInterval seconds" -ForegroundColor White
Write-Host "Max restart attempts: $MaxRestartAttempts" -ForegroundColor White
Write-Host "Press Ctrl+C to stop" -ForegroundColor Yellow
try {
while($true) {
foreach($siteName in $SiteNames) {
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
try {
# Health check
$site = Get-IISSite $siteName -ea Stop
$appPool = Get-IISAppPool $site.Applications[0].ApplicationPoolName -ea 0
$siteOk = $site.State -eq "Started"
$poolOk = $appPool -and $appPool.State -eq "Started"
# HTTP test
$httpOk = $false
$binding = Get-IISSiteBinding $siteName | Where-Object {$_.Protocol -eq "http"} | Select-Object -First 1
if($binding) {
$testUrl = "http://localhost$($binding.BindingInformation.Split(':')[1])"
try {
$response = Invoke-WebRequest $testUrl -UseBasicParsing -TimeoutSec 10
$httpOk = $response.StatusCode -eq 200
} catch { }
}
$allOk = $siteOk -and $poolOk -and $httpOk
if($allOk) {
# Reset failure count on success
if($recoveryState[$siteName].FailureCount -gt 0) {
Write-Host "$timestamp | $siteName recovered successfully" -ForegroundColor Green
$recoveryState[$siteName].FailureCount = 0
$recoveryState[$siteName].RestartAttempts = 0
}
} else {
$recoveryState[$siteName].FailureCount++
$failCount = $recoveryState[$siteName].FailureCount
Write-Host "$timestamp | $siteName failed health check (failure #$failCount) - Site:$siteOk Pool:$poolOk HTTP:$httpOk" -ForegroundColor Red
# Attempt recovery after 2 consecutive failures
if($failCount -ge 2 -and $recoveryState[$siteName].RestartAttempts -lt $MaxRestartAttempts) {
$recoveryState[$siteName].RestartAttempts++
$attemptNum = $recoveryState[$siteName].RestartAttempts
Write-Host "$timestamp | Attempting auto-recovery for $siteName (attempt $attemptNum/$MaxRestartAttempts)" -ForegroundColor Yellow
try {
$success = Invoke-SiteRecovery $siteName
if($success) {
$recoveryState[$siteName].LastRestart = Get-Date
$recoveryState[$siteName].FailureCount = 0
Write-Host "$timestamp | Auto-recovery successful for $siteName" -ForegroundColor Green
# Send success notification
# Send-IISAlert -SiteName $siteName -AlertType "Info" -Message "Auto-recovery successful after $attemptNum attempts"
} else {
Write-Host "$timestamp | Auto-recovery failed for $siteName" -ForegroundColor Red
}
} catch {
Write-Host "$timestamp | Auto-recovery error for $siteName`: $($_.Exception.Message)" -ForegroundColor Red
}
} elseif($recoveryState[$siteName].RestartAttempts -ge $MaxRestartAttempts) {
if($failCount -eq 2) { # Send alert only once
Write-Host "$timestamp | Max restart attempts reached for $siteName - manual intervention required" -ForegroundColor Red
# Send-IISAlert -SiteName $siteName -AlertType "Error" -Message "Site $siteName is down and auto-recovery has failed after $MaxRestartAttempts attempts. Manual intervention required."
}
}
}
} catch {
Write-Host "$timestamp | Error checking $siteName`: $($_.Exception.Message)" -ForegroundColor Red
}
}
Start-Sleep $CheckInterval
}
} catch [System.Management.Automation.PipelineStoppedException] {
Write-Host "`nAuto-recovery service stopped" -ForegroundColor Yellow
}
}
---
function Invoke-BulkSiteOperation {
<#
.SYNOPSIS
Perform operations on multiple sites
.PARAMETER SitePattern
Wildcard pattern to match site names (default: all sites)
.PARAMETER Operation
Operation to perform (Start, Stop, Restart, HealthCheck)
.PARAMETER Parallel
Run operations in parallel for faster execution
#>
param(
[string]$SitePattern = "*",
[ValidateSet("Start","Stop","Restart","HealthCheck","Status")]
[Parameter(Mandatory=$true)]
[string]$Operation,
[switch]$Parallel
)
$sites = Get-IISSite | Where-Object {$_.Name -like $SitePattern}
if($sites.Count -eq 0) {
Write-Host "No sites found matching pattern: $SitePattern" -ForegroundColor Yellow
return
}
Write-Host "Found $($sites.Count) sites matching pattern: $SitePattern" -ForegroundColor Green
$sites | ForEach-Object { Write-Host " - $($_.Name)" -ForegroundColor White }
$confirm = Read-Host "`nProceed with $Operation operation on these sites? (y/N)"
if($confirm -ne 'y') {
Write-Host "Operation cancelled" -ForegroundColor Yellow
return
}
$scriptBlock = {
param($siteName, $operation)
try {
switch($operation) {
"Start" {
Start-IISSite $siteName
return [PSCustomObject]@{Site=$siteName; Operation=$operation; Status="Success"; Message="Site started"}
}
"Stop" {
Stop-IISSite $siteName
return [PSCustomObject]@{Site=$siteName; Operation=$operation; Status="Success"; Message="Site stopped"}
}
"Restart" {
Restart-IISSiteComplete $siteName -Force
return [PSCustomObject]@{Site=$siteName; Operation=$operation; Status="Success"; Message="Site restarted"}
}
"HealthCheck" {
$health = Test-IISSiteHealth $siteName
return [PSCustomObject]@{Site=$siteName; Operation=$operation; Status=$health.OverallHealth; Message="Health: $($health.OverallHealth)"}
}
"Status" {
$site = Get-IISSite $siteName
$appPool = Get-IISAppPool $site.Applications[0].ApplicationPoolName
return [PSCustomObject]@{Site=$siteName; Operation=$operation; Status="Info"; Message="Site: $($site.State), Pool: $($appPool.State)"}
}
}
} catch {
return [PSCustomObject]@{Site=$siteName; Operation=$operation; Status="Error"; Message=$_.Exception.Message}
}
}
Write-Host "`nExecuting $Operation operation..." -ForegroundColor Cyan
if($Parallel -and $PSVersionTable.PSVersion.Major -ge 7) {
# PowerShell 7+ parallel execution
$results = $sites | ForEach-Object -Parallel {
Import-Module WebAdministration,IISAdministration -ErrorAction SilentlyContinue
& $using:scriptBlock $_.Name $using:Operation
} -ThrottleLimit 5
} else {
# Sequential execution
$results = foreach($site in $sites) {
Write-Progress -Activity "Processing Sites" -Status "Working on: $($site.Name)" -PercentComplete (([Array]::IndexOf($sites, $site) / $sites.Count) * 100)
& $scriptBlock $site.Name $Operation
}
Write-Progress -Activity "Processing Sites" -Completed
}
# Display results
Write-Host "`nRESULTS:" -ForegroundColor Yellow
$results | Format-Table -AutoSize
# Summary
$successCount = ($results | Where-Object {$_.Status -eq "Success"}).Count
$errorCount = ($results | Where-Object {$_.Status -eq "Error"}).Count
Write-Host "Summary: $successCount successful, $errorCount failed" -ForegroundColor $(if($errorCount -eq 0){"Green"}else{"Yellow"})
if($errorCount -gt 0) {
Write-Host "`nErrors:" -ForegroundColor Red
$results | Where-Object {$_.Status -eq "Error"} | ForEach-Object {
Write-Host " $($_.Site): $($_.Message)" -ForegroundColor Red
}
}
}
---
# Basic site information
Get-IISSiteInfo "MyWebsite"
Get-IISSiteInfo "*test*" # All sites with "test" in the name
# Quick status check
Get-SiteStatus "MyWebsite"
# Complete restart
Restart-IISSiteComplete "MyWebsite"
Restart-IISSiteComplete "MyWebsite" -RestartAppPool $false # Site only, not app pool
# App pool only restart
Restart-AppPoolOnly -SiteName "MyWebsite"
# Start monitoring
Watch-IISSite "MyWebsite" -IntervalSeconds 30 -AlertThreshold 3 -AutoRestart
# Performance monitoring
Get-SitePerformance "MyWebsite" -Samples 10
Show-SitePerformanceDashboard "MyWebsite" -RefreshSeconds 5
# Health check
Test-IISSiteHealth "MyWebsite" -IncludePerformance
# Log monitoring
Watch-IISLogs "MyWebsite" -ErrorsOnly -Follow
# Smart recovery
Invoke-SiteRecovery "MyWebsite"
# Bulk operations
Invoke-BulkSiteOperation -SitePattern "*prod*" -Operation "HealthCheck"
Invoke-BulkSiteOperation -SitePattern "*test*" -Operation "Restart" -Parallel
# Auto-recovery service
Start-IISAutoRecovery -SiteNames @("CriticalSite1", "CriticalSite2") -CheckInterval 30
# Set up continuous monitoring for critical sites
$criticalSites = @("MainWebsite", "APIService", "AdminPortal")
# Health check all critical sites
foreach($site in $criticalSites) {
Write-Host "=== $site ===" -ForegroundColor Cyan
Test-IISSiteHealth $site -IncludePerformance
Write-Host ""
}
# Start auto-recovery for critical sites
Start-IISAutoRecovery -SiteNames $criticalSites -CheckInterval 60 -MaxRestartAttempts 3
# Monitor specific site with real-time dashboard
Show-SitePerformanceDashboard "MainWebsite" -RefreshSeconds 10
# Watch logs for errors in real-time
Watch-IISLogs "MainWebsite" -ErrorsOnly -Follow
# Create a maintenance script
function Invoke-IISMaintenance {
Write-Host "Starting IIS maintenance routine..." -ForegroundColor Green
# Health check all sites
$sites = Get-IISSite
foreach($site in $sites) {
Write-Host "Checking: $($site.Name)" -ForegroundColor Yellow
$health = Test-IISSiteHealth $site.Name
if($health.OverallHealth -ne "Healthy") {
Write-Host " Issues found with $($site.Name)" -ForegroundColor Red
# Send-IISAlert -SiteName $site.Name -AlertType "Warning" -Message "Health check found issues: $($health.Errors -join ', ')"
}
}
# Clean up old log files (older than 30 days)
$logPath = "C:\inetpub\logs\LogFiles"
Get-ChildItem $logPath -Recurse -Filter "*.log" | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-30)} | Remove-Item -Force
Write-Host "Maintenance completed" -ForegroundColor Green
}
# Run maintenance
Invoke-IISMaintenance
---
To use these functions:
1. Add to PowerShell Profile:
notepad $PROFILE
# Paste all functions, save, then:
. $PROFILE
2. Or save as module:
# Save all functions to IISUtilities.psm1
Import-Module .\IISUtilities.psm1
3. Start monitoring immediately:
Watch-IISSite "MyWebsite" -AutoRestart
These functions provide enterprise-level IIS monitoring and management capabilities with real-time dashboards, automated recovery, health checks, and comprehensive logging - all with simple PowerShell commands!