Public/Get-IISCertificateReport.ps1
|
function Get-IISCertificateReport { <# .SYNOPSIS Reports on certificates bound to IIS sites. .DESCRIPTION Connects to one or more computers via Invoke-Command and enumerates IIS HTTPS bindings using Get-WebBinding. For each binding that references a certificate hash, the function looks up the certificate in the machine Personal store and returns binding metadata alongside certificate details and an expiry finding. Requires the WebAdministration or IISAdministration module on the target machine and WinRM access for remote computers. .PARAMETER ComputerName One or more computer names to scan. Accepts pipeline input. Defaults to localhost. .EXAMPLE Get-IISCertificateReport -ComputerName Web01,Web02 Lists all HTTPS-bound certificates on two IIS servers. .EXAMPLE 'Web01','Web02' | Get-IISCertificateReport Pipeline input scanning. .OUTPUTS PSCustomObject with properties: SiteName, Binding, Protocol, Subject, Thumbprint, NotAfter, DaysRemaining, ComputerName, Finding. #> [CmdletBinding()] param( [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)] [string[]]$ComputerName = @('localhost') ) begin { Write-Verbose 'Get-IISCertificateReport - scanning IIS bindings' $scriptBlock = { # Ensure the IIS provider is available $iisModule = Get-Module -ListAvailable -Name WebAdministration, IISAdministration | Select-Object -First 1 if (-not $iisModule) { Write-Warning "No IIS management module found on $env:COMPUTERNAME. Skipping." return } Import-Module $iisModule.Name -ErrorAction Stop $now = Get-Date Get-WebBinding -Protocol https -ErrorAction SilentlyContinue | ForEach-Object { $binding = $_ $bindingInfo = $_.bindingInformation # e.g. "*:443:www.contoso.com" $certHash = $_.certificateHash $certStore = $_.certificateStoreName if (-not $certStore) { $certStore = 'My' } # Resolve the parent site name $siteName = (Get-Website | Where-Object { $_.Bindings.Collection.bindingInformation -contains $bindingInfo }).Name if (-not $siteName) { $siteName = 'Unknown' } if ($certHash) { $thumbprint = ($certHash | ForEach-Object { '{0:X2}' -f $_ }) -join '' if (-not $thumbprint -or $thumbprint -eq '00') { # Sometimes the hash is already a hex string $thumbprint = $certHash } $cert = Get-ChildItem -Path "Cert:\LocalMachine\$certStore" -ErrorAction SilentlyContinue | Where-Object { $_.Thumbprint -eq $thumbprint } if ($cert) { $daysRemaining = ($cert.NotAfter - $now).Days $finding = if ($cert.NotAfter -lt $now) { 'EXPIRED' } elseif ($daysRemaining -le 7) { 'CRITICAL' } elseif ($daysRemaining -le 30) { 'WARNING' } else { 'OK' } [PSCustomObject]@{ SiteName = $siteName Binding = $bindingInfo Protocol = 'https' Subject = $cert.Subject Thumbprint = $cert.Thumbprint NotAfter = $cert.NotAfter DaysRemaining = $daysRemaining ComputerName = $env:COMPUTERNAME Finding = $finding } } else { [PSCustomObject]@{ SiteName = $siteName Binding = $bindingInfo Protocol = 'https' Subject = '** CERTIFICATE NOT FOUND **' Thumbprint = $thumbprint NotAfter = $null DaysRemaining = -1 ComputerName = $env:COMPUTERNAME Finding = 'MISSING' } } } } } } process { foreach ($computer in $ComputerName) { Write-Verbose "Scanning IIS bindings on $computer" try { $isLocal = $computer -eq 'localhost' -or $computer -eq $env:COMPUTERNAME -or $computer -eq '.' if ($isLocal) { $results = & $scriptBlock } else { $results = Invoke-Command -ComputerName $computer ` -ScriptBlock $scriptBlock ` -ErrorAction Stop } if ($results) { $results | ForEach-Object { $_ } } else { Write-Verbose "No HTTPS bindings found on $computer." } } catch { Write-Warning "Failed to scan IIS on ${computer}: $_" } } } end { Write-Verbose 'Get-IISCertificateReport complete.' } } |