Skip to content

Test-IISHealth.ps1

Niveau : Intermรฉdiaire

Vรฉrification complรจte d'un serveur IIS Windows.


Description

Ce script vรฉrifie l'รฉtat d'un serveur IIS : - Service W3SVC et pools d'applications - Sites web et bindings - Certificats SSL - Logs et espace disque - Performance (requรชtes actives, connexions)


Prรฉrequis

  • Systรจme : Windows Server 2016+ avec rรดle IIS
  • PowerShell : Version 5.1 minimum
  • Permissions : Droits administrateur sur le serveur IIS
  • Modules : WebAdministration (installรฉ automatiquement avec IIS)

Cas d'Usage

  • Monitoring web : Surveillance quotidienne des applications pools et sites IIS
  • Troubleshooting IIS : Diagnostiquer les pools arrรชtรฉs ou sites inaccessibles
  • Alertes certificats : Dรฉtecter les certificats SSL qui vont expirer
  • Performance analysis : Analyser les requรชtes actives et l'utilisation mรฉmoire

Script

#Requires -Version 5.1
<#
.SYNOPSIS
    Health check d'un serveur IIS.

.DESCRIPTION
    Vรฉrifie l'รฉtat complet d'un serveur IIS incluant
    les sites, pools, certificats SSL et performance.

.PARAMETER ComputerName
    Nom du serveur IIS (dรฉfaut: localhost).

.PARAMETER CheckSSL
    Vรฉrifier les certificats SSL.

.PARAMETER CertWarningDays
    Jours avant expiration pour alerte certificat (dรฉfaut: 30).

.EXAMPLE
    .\Test-IISHealth.ps1
    Vรฉrifie le serveur IIS local.

.EXAMPLE
    .\Test-IISHealth.ps1 -CheckSSL -CertWarningDays 60
    Vรฉrifie IIS avec contrรดle SSL.

.NOTES
    Author: ShellBook
    Version: 1.0
#>

[CmdletBinding()]
param(
    [Parameter()]
    [string]$ComputerName = "localhost",

    [Parameter()]
    [switch]$CheckSSL,

    [Parameter()]
    [int]$CertWarningDays = 30
)

# Importer le module WebAdministration
Import-Module WebAdministration -ErrorAction Stop

#region Functions
function Write-Check {
    param(
        [string]$Name,
        [ValidateSet('Pass', 'Warn', 'Fail', 'Info')]
        [string]$Status,
        [string]$Message
    )

    $icons = @{
        'Pass' = @('[OK]  ', 'Green')
        'Warn' = @('[WARN]', 'Yellow')
        'Fail' = @('[FAIL]', 'Red')
        'Info' = @('[INFO]', 'Cyan')
    }

    Write-Host $icons[$Status][0] -ForegroundColor $icons[$Status][1] -NoNewline
    Write-Host " $Name" -NoNewline
    if ($Message) { Write-Host " - $Message" -ForegroundColor Gray }
    else { Write-Host "" }

    switch ($Status) {
        'Pass' { $script:passed++ }
        'Warn' { $script:warnings++ }
        'Fail' { $script:failed++ }
    }
    $script:total++
}
#endregion

#region Main
$script:total = 0
$script:passed = 0
$script:warnings = 0
$script:failed = 0

Write-Host ""
Write-Host ("=" * 65) -ForegroundColor Cyan
Write-Host "  IIS HEALTH CHECK" -ForegroundColor Green
Write-Host ("=" * 65) -ForegroundColor Cyan
Write-Host "  Server: $ComputerName"
Write-Host "  Date: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Host ("-" * 65) -ForegroundColor Cyan

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# CHECK 1: Services IIS
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Write-Host "`n[Services IIS]" -ForegroundColor Cyan

$iisServices = @(
    @{ Name = 'W3SVC'; Display = 'World Wide Web Publishing' }
    @{ Name = 'WAS'; Display = 'Windows Process Activation' }
    @{ Name = 'IISADMIN'; Display = 'IIS Admin Service' }
)

foreach ($svc in $iisServices) {
    $service = Get-Service -Name $svc.Name -ErrorAction SilentlyContinue
    if ($service -and $service.Status -eq 'Running') {
        Write-Check -Name $svc.Display -Status Pass -Message "Running"
    } elseif ($service) {
        Write-Check -Name $svc.Display -Status Fail -Message $service.Status
    } else {
        Write-Check -Name $svc.Display -Status Info -Message "Not installed"
    }
}

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# CHECK 2: Application Pools
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Write-Host "`n[Application Pools]" -ForegroundColor Cyan

$appPools = Get-ChildItem IIS:\AppPools

$runningPools = ($appPools | Where-Object { $_.State -eq 'Started' }).Count
$stoppedPools = ($appPools | Where-Object { $_.State -eq 'Stopped' }).Count

Write-Check -Name "Total App Pools" -Status Info -Message "$($appPools.Count)"

if ($stoppedPools -gt 0) {
    Write-Check -Name "Stopped Pools" -Status Warn -Message "$stoppedPools pool(s)"

    foreach ($pool in ($appPools | Where-Object { $_.State -eq 'Stopped' })) {
        Write-Host "       - $($pool.Name)" -ForegroundColor Yellow
    }
} else {
    Write-Check -Name "All Pools Running" -Status Pass -Message "$runningPools pool(s)"
}

# Vรฉrifier la configuration des pools
foreach ($pool in $appPools | Where-Object { $_.State -eq 'Started' }) {
    $recycling = $pool.Recycling.PeriodicRestart
    $processModel = $pool.ProcessModel

    # Alerte si recycling dรฉsactivรฉ
    if ($recycling.Time.TotalMinutes -eq 0 -and $recycling.Schedule.Count -eq 0) {
        Write-Check -Name "Pool $($pool.Name)" -Status Warn -Message "No recycling configured"
    }

    # Mode pipeline
    $pipelineMode = $pool.ManagedPipelineMode
    $runtimeVersion = $pool.ManagedRuntimeVersion
    Write-Host "       $($pool.Name): $pipelineMode, $runtimeVersion" -ForegroundColor Gray
}

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# CHECK 3: Sites Web
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Write-Host "`n[Sites Web]" -ForegroundColor Cyan

$sites = Get-ChildItem IIS:\Sites

$runningSites = ($sites | Where-Object { $_.State -eq 'Started' }).Count
$stoppedSites = ($sites | Where-Object { $_.State -eq 'Stopped' }).Count

Write-Check -Name "Total Sites" -Status Info -Message "$($sites.Count)"

if ($stoppedSites -gt 0) {
    Write-Check -Name "Stopped Sites" -Status Warn -Message "$stoppedSites site(s)"
}

foreach ($site in $sites) {
    $bindings = $site.Bindings.Collection
    $bindingInfo = ($bindings | ForEach-Object { $_.bindingInformation }) -join ", "

    if ($site.State -eq 'Started') {
        Write-Check -Name "Site $($site.Name)" -Status Pass -Message "Running"
    } else {
        Write-Check -Name "Site $($site.Name)" -Status Warn -Message $site.State
    }
    Write-Host "       Bindings: $bindingInfo" -ForegroundColor Gray
    Write-Host "       Path: $($site.PhysicalPath)" -ForegroundColor Gray
}

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# CHECK 4: Certificats SSL
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
if ($CheckSSL) {
    Write-Host "`n[Certificats SSL]" -ForegroundColor Cyan

    $sslBindings = Get-ChildItem IIS:\SslBindings -ErrorAction SilentlyContinue

    if ($sslBindings) {
        foreach ($binding in $sslBindings) {
            $cert = Get-ChildItem Cert:\LocalMachine\My |
                Where-Object { $_.Thumbprint -eq $binding.Thumbprint }

            if ($cert) {
                $daysToExpiry = ($cert.NotAfter - (Get-Date)).Days
                $subject = $cert.Subject -replace 'CN=', ''

                if ($daysToExpiry -lt 0) {
                    Write-Check -Name "Cert $subject" -Status Fail `
                        -Message "EXPIRED ($($cert.NotAfter.ToString('yyyy-MM-dd')))"
                } elseif ($daysToExpiry -lt $CertWarningDays) {
                    Write-Check -Name "Cert $subject" -Status Warn `
                        -Message "Expires in $daysToExpiry days"
                } else {
                    Write-Check -Name "Cert $subject" -Status Pass `
                        -Message "Valid ($daysToExpiry days)"
                }
            }
        }
    } else {
        Write-Check -Name "SSL Bindings" -Status Info -Message "None configured"
    }
}

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# CHECK 5: Espace disque logs
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Write-Host "`n[Logs IIS]" -ForegroundColor Cyan

$logPath = (Get-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
    -Filter 'system.applicationHost/sites/siteDefaults/logFile' -Name 'directory').Value

$logPath = [System.Environment]::ExpandEnvironmentVariables($logPath)

if (Test-Path $logPath) {
    $logSize = (Get-ChildItem -Path $logPath -Recurse -File -ErrorAction SilentlyContinue |
        Measure-Object -Property Length -Sum).Sum
    $logSizeGB = [math]::Round($logSize / 1GB, 2)

    Write-Check -Name "Log Directory" -Status Info -Message $logPath

    if ($logSizeGB -gt 10) {
        Write-Check -Name "Log Size" -Status Warn -Message "$logSizeGB GB (consider cleanup)"
    } else {
        Write-Check -Name "Log Size" -Status Pass -Message "$logSizeGB GB"
    }

    # Fichiers de log rรฉcents
    $recentLogs = Get-ChildItem -Path $logPath -Recurse -File -ErrorAction SilentlyContinue |
        Where-Object { $_.LastWriteTime -gt (Get-Date).AddHours(-24) }
    Write-Host "       Recent logs (24h): $($recentLogs.Count) files" -ForegroundColor Gray
}

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# CHECK 6: Performance
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Write-Host "`n[Performance]" -ForegroundColor Cyan

try {
    # Requรชtes actives
    $activeRequests = (Get-Counter '\Web Service(_Total)\Current Connections' -ErrorAction Stop).CounterSamples.CookedValue
    Write-Check -Name "Active Connections" -Status Info -Message "$activeRequests"

    # Requรชtes par seconde
    $reqPerSec = (Get-Counter '\Web Service(_Total)\Total Method Requests/sec' -ErrorAction Stop).CounterSamples.CookedValue
    Write-Check -Name "Requests/sec" -Status Info -Message "$([math]::Round($reqPerSec, 2))"

    # Mรฉmoire des workers
    $w3wpProcesses = Get-Process -Name w3wp -ErrorAction SilentlyContinue
    if ($w3wpProcesses) {
        $totalMemoryMB = [math]::Round(($w3wpProcesses | Measure-Object -Property WorkingSet64 -Sum).Sum / 1MB, 0)
        Write-Check -Name "Worker Processes" -Status Info -Message "$($w3wpProcesses.Count) process(es), $totalMemoryMB MB"
    }
}
catch {
    Write-Check -Name "Performance Counters" -Status Warn -Message "Could not retrieve"
}

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# CHECK 7: Configuration
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Write-Host "`n[Configuration]" -ForegroundColor Cyan

# Vรฉrifier les modules installรฉs
$modules = Get-WebConfiguration -Filter 'system.webServer/modules' -PSPath 'MACHINE/WEBROOT/APPHOST'
Write-Host "       Modules loaded: $($modules.Collection.Count)" -ForegroundColor Gray

# Compression activรฉe
$compression = Get-WebConfiguration -Filter 'system.webServer/urlCompression' -PSPath 'MACHINE/WEBROOT/APPHOST'
if ($compression.doStaticCompression -and $compression.doDynamicCompression) {
    Write-Check -Name "Compression" -Status Pass -Message "Static & Dynamic enabled"
} elseif ($compression.doStaticCompression) {
    Write-Check -Name "Compression" -Status Info -Message "Static only"
} else {
    Write-Check -Name "Compression" -Status Warn -Message "Disabled"
}

# Request filtering
$requestFiltering = Get-WebConfiguration -Filter 'system.webServer/security/requestFiltering' -PSPath 'MACHINE/WEBROOT/APPHOST'
if ($requestFiltering) {
    Write-Check -Name "Request Filtering" -Status Pass -Message "Enabled"
} else {
    Write-Check -Name "Request Filtering" -Status Warn -Message "Not configured"
}

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# Rร‰SUMร‰
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Write-Host "`n" + ("=" * 65) -ForegroundColor Cyan
Write-Host "  Rร‰SUMร‰" -ForegroundColor Green
Write-Host ("=" * 65) -ForegroundColor Cyan

Write-Host "  Checks: $script:total total"
Write-Host "    - " -NoNewline; Write-Host "Passed: $script:passed" -ForegroundColor Green
Write-Host "    - " -NoNewline; Write-Host "Warnings: $script:warnings" -ForegroundColor Yellow
Write-Host "    - " -NoNewline; Write-Host "Failed: $script:failed" -ForegroundColor Red

Write-Host ""
if ($script:failed -gt 0) {
    Write-Host "  IIS STATUS: CRITICAL" -ForegroundColor Red
    exit 2
} elseif ($script:warnings -gt 0) {
    Write-Host "  IIS STATUS: DEGRADED" -ForegroundColor Yellow
    exit 1
} else {
    Write-Host "  IIS STATUS: HEALTHY" -ForegroundColor Green
    exit 0
}
#endregion

Utilisation

# Vรฉrifier le serveur IIS local
.\Test-IISHealth.ps1

# Avec vรฉrification SSL
.\Test-IISHealth.ps1 -CheckSSL

# Alerte certificat 60 jours avant expiration
.\Test-IISHealth.ps1 -CheckSSL -CertWarningDays 60

Exemple de Sortie

=================================================================
  IIS HEALTH CHECK
=================================================================
  Server: WEB01
  Date: 2025-12-01 18:48:33
-----------------------------------------------------------------

[Services IIS]
[OK]   World Wide Web Publishing - Running
[OK]   Windows Process Activation - Running
[OK]   IIS Admin Service - Running

[Application Pools]
[INFO] Total App Pools - 5
[WARN] Stopped Pools - 1 pool(s)
       - LegacyApp_Pool
[WARN] Pool API_Pool - No recycling configured
       DefaultAppPool: Integrated, v4.0
       WebApp_Pool: Integrated, v4.0
       API_Pool: Integrated, v4.0

[Sites Web]
[INFO] Total Sites - 4
[OK]   Site Default Web Site - Running
       Bindings: *:80:, *:443:
       Path: C:\inetpub\wwwroot
[OK]   Site WebApp - Running
       Bindings: *:443:webapp.corp.local
       Path: D:\Apps\WebApp
[OK]   Site API - Running
       Bindings: *:443:api.corp.local
       Path: D:\Apps\API
[WARN] Site Legacy - Stopped
       Bindings: *:8080:
       Path: D:\Apps\Legacy

[Certificats SSL]
[OK]   Cert webapp.corp.local - Valid (187 days)
[OK]   Cert api.corp.local - Valid (187 days)
[WARN] Cert legacy.corp.local - Expires in 18 days

[Logs IIS]
[INFO] Log Directory - C:\inetpub\logs\LogFiles
[OK]   Log Size - 2.45 GB
       Recent logs (24h): 12 files

[Performance]
[INFO] Active Connections - 127
[INFO] Requests/sec - 45.23
[INFO] Worker Processes - 4 process(es), 892 MB

[Configuration]
       Modules loaded: 42
[OK]   Compression - Static & Dynamic enabled
[OK]   Request Filtering - Enabled

=================================================================
  Rร‰SUMร‰
=================================================================
  Checks: 18 total
    - Passed: 12
    - Warnings: 4
    - Failed: 0

  IIS STATUS: DEGRADED

Voir Aussi