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.'
    }
}