IIS Website certificates information and report monitoring

Hi everyone,

I've found that the default IIS SSL Certificate SAM template only monitors the first website within IIS, and not any others. I also found that some of the information gathered was not very useful when trying  to work out which certificate was assigned to which website.

Here is my PowerShell script that gathers some information which I think help identify what is being used for a particular website.

In SolarWinds Application Monitoring create a application monitoring template and assign a PowerShell Monitoring component. I've set the monitoring template to poll every day (Polling Frequency: 14400)

Settings Information  (Agentless) :-

Component Description:

*******

Checks for the expiry of the IIS SSL Certificates for Sites bound to HTTPS.
Poll Systems for Certificates to alert (Static Threshold) "WARNING" if they will expires in 35 days time and "CRITICAL" if they will expire within 21 days. Leave Response Time Threshold values blank.
Enter the "${Node.Caption} , Site ID found in IIS as the "Script Arguments". Configured for Site ID = 1

ie. ${node.Caption},1

*******

Credential for monitoring:  <Inherit from template>

Script Arguments:

${node.Caption},1
as per the description, if you website is ID 2 then change the digit to the Website ID (found in IIS).

 Execution Mode:  I've got mine set to Local Host

Run the script under specified account:  option ticked.

$MyScript = {
    $SiteID = $args
    try
    {
    $objCert = $null
        $objCert = Get-WebBinding -Protocol https | Where-Object {($_.ItemXPath -replace '(?:.*?)id=''([^'']*)(?:.*)', '$1') -eq $SiteID}| Select-Object bindingInformation, certificateHash, certificateStoreName, ItemXPath

        if (($objCert -eq "") -or ($Null -eq $objCert))
        {
            $strMessage = "No sites are bound to a HTTPS Procotol"
        }
    
            if ($objCert -is [System.Array])
        {
            $strCertPath = "Cert:\LocalMachine\{0}\{1}" -f $objCert.certificateStoreName[0], $objCert.certificateHash[0]
        }
        else
        {
            $strCertPath = "Cert:\LocalMachine\{0}\{1}" -f $objCert.certificateStoreName, $objCert.certificateHash
        }
        $objCertAll = Get-ChildItem -Path $strCertPath | Select-Object -Property Issuer,notafter,FriendlyName,DnsNameList,Subject

        $SiteID =  ($objCert[0].ItemXPath -replace '(?:.*?)id=''([^'']*)(?:.*)', '$1').ToString().Trim()
        $WebSite = ($objCert[0].ItemXPath -replace '(?:.*?)name=''([^'']*)(?:.*)', '$1').ToString().Trim()
        $objSiteBinding = $objCert[0].bindingInformation.substring($objCert[0].bindingInformation.IndexOf(":")+1)
        $SiteBinding = $objSiteBinding.substring(0,$objSiteBinding.IndexOf(":"))
        $CertExpiresDays = ($objCertAll.notAfter – (Get-Date)).Days
        $CertExpiryDate = (Get-Date).AddDays($CertExpiresDays).ToString('dd/MM/yyyy')
        $CertFriendlyName = $objCertAll.FriendlyName.Trim()
        $CertSubject = $objCertAll.Subject
        $CertDNSNames = [system.string]::Join(", ", $objCertAll.DnsNameList.Unicode)
        $CertThumbprint = $objCert.certificateHash

        Write-Host ("Message.Web_SiteID: {0}" -f $WebSite)
        Write-Host ("Statistic.Web_SiteID: {0}" -f $SiteID)

        Write-Host ("Message.Site_Port_Binding: {0}" -f $SiteBinding)
        Write-Host ("Statistic.Site_Port_Binding: {0}" -f $SiteBinding)

        Write-Host ("Message.Cert_Expires_Days: {0}" -f $CertExpiresDays)
        Write-Host ("Statistic.Cert_Expires_Days: {0}" -f $CertExpiresDays)

        Write-Host ("Message.Cert_Expiry_Date: {0}" -f $CertExpiryDate)
        Write-Host "Statistic.Cert_Expiry_Date: 0"

        Write-Host ("Message.Cert_Friendly_Name: {0}" -f $CertFriendlyName)
        Write-Host "Statistic.Cert_Friendly_Name: 0"

        Write-Host ("Message.Cert_Subject: {0}" -f $CertSubject)
        Write-Host "Statistic.Cert_Subject: 0"

        Write-Host ("Message.Cert_DNS_Names: {0}" -f $CertDNSNames)
        Write-Host "Statistic.Cert_DNS_Names: 0"

        Write-Host ("Message.Cert_Thumbprint: {0}" -f $CertThumbprint)
        Write-Host "Statistic.Cert_Thumbprint: 0"
    }
    Catch
    {
        $strMessage= "Unable to detect a IIS SSL certificate."
        Write-Host "Message.Site: $strMessage"
        $iSWStatistic = 0
        Write-Host "Statistic.Site: $iSWStatistic"
    }
}

$computerName = $args[0]

$iWebsiteID = $args[1]

if (Test-Connection -ComputerName $computerName -Quiet -Count 1)
{
    Invoke-Command -ComputerName $computerName -Credential '${CREDENTIAL}' -ScriptBlock $MyScript -ArgumentList $iWebsiteID
}

Settings Information  (Agent) :-

Component Description:

*******

Checks for the expiry of the IIS SSL Certificates for Sites bound to HTTPS.
Poll Systems for Certificates to alert (Static Threshold) "WARNING" if they will expires in 35 days time and "CRITICAL" if they will expire within 21 days. Leave Response Time Threshold values blank.
Site ID found in IIS as the "Script Arguments". Configured for Site ID = 1

*******

Credential for monitoring:  <None>

Script Arguments: 1
as per the description, if you website is ID 2 then change the digit to the Website ID (found in IIS).

 

Execution Mode:  I've got mine set to Local Host

Run the script under specified account:  option Unticked.

Edit the script and remove the following lines, as they are not required when a system has an agent installed.

Line 1  = $MyScript = {

Lines 65 and below (to the end) = 

}

$computerName = $args[0]

$iWebsiteID = $args[1]

if (Test-Connection -ComputerName $computerName -Quiet -Count 1)
{
Invoke-Command -ComputerName $computerName -Credential '${CREDENTIAL}' -ScriptBlock $MyScript -ArgumentList $iWebsiteID
}

When you insert the script, carry out at test on a node that you know has an IIS Cert installed.
You should then have 8x Script Outputs. I remove the "_" (underscores) in the display name but that is a personal preference.
Under the "Cert_Expires_Days" output set your threshold. we have warning at "Less than or equal to = 35" and critical set to 21.

The statistical data for "Cert DNS Names, Cert Expiry Date, Cert Friendly Name, Cert Subject, Cert Thumbprint" is set to 0 (zero) as is the string value you are interested in.
"Cert Expires Days" is the amount of days before the Certificate will expire.
"Site Port Binding" is the SSL port number assigned to the website (useful if it's not the default 443
"Web SiteID"  will be the IIS Site ID number.

Now thats great, but we also needed a weekly report running, to be more pro-active and renew the certificates before the site expired.
Here is the SWQL code to generate the outputs for a custom table.

SELECT [Node].Caption,
[Node].DetailsUrl,
[Web_Site_ID].WebSiteID as [Web Site Name],
[Web_Cert_Expiry_Days].WebCertExpiryInDays as [Cert Expires In Days],
CertExpiryDate.ExpiryDate as [Cert Expiry Date],
CertThumbprint.SSLThumbPrint as [Cert Thumbprint],
CertSubject.CSubject As [Cert Subject]

FROM Orion.APM.GenericApplication AS [APM_GA]
JOIN Orion.Nodes [Node] ON [APM_GA].NodeID = [Node].NodeID

JOIN ( Select DISTINCT [APM_WebSite_ID].Component.Application.NodeID,
        [APM_WebSite_ID].StringData As [WebSiteID]
        From Orion.APM.MultipleStatisticData AS [APM_WebSite_ID]
        Where [APM_WebSite_ID].Name = 'Web_SiteID') [Web_Site_ID] on [Web_Site_ID].NodeID = [APM_GA].NodeID

JOIN ( Select DISTINCT [APM_Website_Cert_ExpiryDays].Component.Application.NodeID,
        [APM_Website_Cert_ExpiryDays].NumericData As [WebCertExpiryInDays]
        From Orion.APM.MultipleStatisticData AS [APM_Website_Cert_ExpiryDays]
        Where [APM_Website_Cert_ExpiryDays].Name = 'Cert_Expires_Days') [Web_Cert_Expiry_Days] on [Web_Cert_Expiry_Days].NodeID = [APM_GA].NodeID

JOIN ( Select DISTINCT [APM_Website_Cert_ExpiryDate].Component.Application.NodeID,
        [APM_Website_Cert_ExpiryDate].StringData As [ExpiryDate]
        From Orion.APM.MultipleStatisticData AS [APM_Website_Cert_ExpiryDate]
        Where [APM_Website_Cert_ExpiryDate].Name = 'Cert_Expiry_Date') CertExpiryDate on CertExpiryDate.NodeID = [APM_GA].NodeID

JOIN ( Select DISTINCT [APM_Website_Cert_Thumbprint].Component.Application.NodeID,
        [APM_Website_Cert_Thumbprint].StringData As [SSLThumbprint]
        From Orion.APM.MultipleStatisticData AS [APM_Website_Cert_Thumbprint]
        Where [APM_Website_Cert_Thumbprint].Name = 'Cert_Thumbprint') CertThumbprint on CertThumbprint.NodeID = [APM_GA].NodeID

JOIN ( Select DISTINCT [APM_Website_Cert_Subject].Component.Application.NodeID,
        [APM_Website_Cert_Subject].StringData As [CSubject]
        From Orion.APM.MultipleStatisticData AS [APM_Website_Cert_Subject]
        Where [APM_Website_Cert_Subject].Name = 'Cert_Subject') CertSubject on CertSubject.NodeID = [APM_GA].NodeID

WHERE ([APM_GA].Name = '< ENTER THE NAME OF THE APPLICATION MONITOR TEMPLATE >')
    and [Web_Cert_Expiry_Days].WebCertExpiryInDays <= 60 
WITH NOLOCK

in the table layout, I have updated the "Node" option. click on Advanced and in the Add display settings, change to "Details Page Link".

I then change the Sort option to Cert Expires (ascending) and then Node (ascending)

Group by Node

Here are the views you get.
Application Template / Component View

Report View

I also have something very similar for SQL Instances that use SSL Certs.

Parents Reply Children