Patrick Burwell
Patrick Burwell

Reputation: 171

How can I use Powershell to find when an SSL certificate expires for ONLY IIS for a list of servers from OU?

I have this section of code that if I can merely get the script to ONLY reply with Subject that exists (which indicates the IIS cert), then I can be done... (I have the OU enumeration, and the Invoke section down, and the email of the file for scheduling in a task): [NOTE: I have the expiration set to 500 days so I can then use the script later to merely find specific expiration times] [NOTE2: $day is set in my $profile to '$day = Get-Date -Format yyyyMMdd']

    $serverlist = $serverListpath.Name
    foreach($server in $serverlist){
        if($server -like '#*')
        {
            continue
        }
    
    $threshold = 500   #Number of days to look for expiring certificates
    $deadline = (Get-Date).AddDays($threshold)   #Set deadline date
    $p = ($c++/$server.count) * 100
     Write-Progress -Activity "Checking $._" -Status "$p % completed" -PercentComplete $p;
     if(Test-Connection -ComputerName $server -Count 2 -Quiet){
     #$server = "KnownIISServerHostname" #<-- to test with a hostname
    Invoke-Command -Verbose -ComputerName $server { Dir Cert:\LocalMachine\My } |`
foreach {
    If ($_.NotAfter -le $deadline) { 
$_ | Select *| select PSComputerName, Subject, NotAfter, @{Label="Expires In (Days)";Expression={($_.NotAfter - (Get-Date)).Days}} }
    }|`
select PSComputerName,Subject, NotAfter, @{Label="Expires In (Days)";Expression={($_.NotAfter - (Get-Date)).Days}} |`
    export-csv -Force -Append -Encoding ASCII -NoTypeInformation .\output\$day-ExpiringIISSSLCerts.csv
    }
    }

So where do I tweak this to get the reply to ONLY have existing "Subject" fields; Not to get the null subject field replies (which are RDP certificates)

Upvotes: 1

Views: 8317

Answers (6)

Patrick Burwell
Patrick Burwell

Reputation: 171

#D:\batch\checkCertExpDate.ps1
    $day = Get-Date -Format yyyyMMdd
    Set-Location d:\batch
    $serverlist = gc ".\serverlist.txt"
    foreach($server in $serverlist)
    {
    $threshold = 45   #Number of days to look for expiring certificates
    $deadline = (Get-Date).AddDays($threshold)   #Set deadline date
    Invoke-Command $server { Dir Cert:\LocalMachine\My } | foreach {
    If ($_.NotAfter -le $deadline) { $_ | Select Issuer, Subject, NotAfter, @{Label="Expires In (Days)";Expression={($_.NotAfter - (Get-Date)).Days}} }
    }|select -expandproperty Subject|out-file .\output\$day-ExpiringIISSSLCerts.txt -Encoding ascii -Append
    }
# Start mail send
$log = "d:\batch\output\$day-ExpiringIISSSLCerts.txt"
    if(Test-Path -Path $log){

$smtpServer = "smtp.domain.com"
$messageSubject = "Verify SSL Cert Check Report - " + $env:computername 
$message = New-Object System.Net.Mail.MailMessage
$message.From = "[email protected]"
$message.To.Add("[email protected]")
$message.Subject = $messageSubject 
$message.IsBodyHTML = $true 
$message.Body = "<head><pre>$style</pre></head>" 
$message.Body += "Cert Check Report - " + $env:computername
$message.Body += Get-Date
$message.Body += "<br><b>Expiring Non-Prod Verify SSL Certificates Report from " + $env:computername + "</b>"
$message.Attachments.Add($log)
$smtp = New-Object Net.Mail.SmtpClient($smtpServer) 
$smtp.Send($message)
}
$result = Get-content $log
write-host $result |format-list -View table

Upvotes: 0

Patrick Burwell
Patrick Burwell

Reputation: 171

#checkCertExpDate-manual.ps1
$day = Get-Date -Format yyyyMMdd
$threshold = 5000   #Number of days to look for expiring certificates
$deadline = (Get-Date).AddDays($threshold)   #Set deadline date
Dir Cert:\LocalMachine\My | foreach {
If ($_.NotAfter -le $deadline) { $_ | Select Issuer, Subject, NotAfter, @{Label="Expires In (Days)";Expression={($_.NotAfter - (Get-Date)).Days}} }
}

Then you just grep for the name:

.\checkCertExpDate-manual.ps1|Select-String -pattern "companyname"

Now, I can set the '$threshold' to whatever I want...

I invoke this remotely, after I copied to every server, and wrote the output to a log I then email to myself automatically every week from a scheduled task.

Upvotes: 0

spencerstewart
spencerstewart

Reputation: 151

Similar to @bruce-zhangs's excellent answer but gets the certs in use first, then retrieves only those from the appropriate certificate stores (instead of only looking at the My cert store):

Import-Module WebAdministration
$CertsInUse = Get-Childitem -Path IIS:\SslBindings
$CertsInUse | foreach{Get-Childitem –path Cert:\LocalMachine\$($_.Store)\$($_.Thumbprint)} | Select-Object -Property FriendlyName,Subject, @{n=’ExpireInDays’;e={($_.notafter – (Get-Date)).Days}}

Here it is with a more verbose foreach:

Import-Module WebAdministration
$CertsInUse = Get-Childitem -Path IIS:\SslBindings
$CertsDetails = @()
foreach ($Cert in $CertsInUse) {
    $CertsDetails += Get-ChildItem -Path Cert:\LocalMachine\$($Cert.Store)\$($Cert.Thumbprint)
}
$CertsDetails | Select-Object -Property FriendlyName,Subject, @{n=’ExpireInDays’;e={($_.notafter – (Get-Date)).Days}}

Upvotes: 0

Patrick Burwell
Patrick Burwell

Reputation: 171

#Complete LOCAL run script. Call this in a Foreach Invoke-command.

$CertAll=GCI -Path Cert:\LocalMachine\My
$CertInUse= (GCI IIS:SSLBindings)
$CertSame=Compare-Object -ReferenceObject $CertAll -DifferenceObject $CertInUse -Property ThumbPrint -IncludeEqual -ExcludeDifferent
#$CertSame=Compare-Object -ReferenceObject $CertAll -Property ThumbPrint -IncludeEqual -ExcludeDifferent
$CertSame | foreach{GCI -filter "" –path Cert:\LocalMachine\My\$($_.thumbprint)} | Select-Object -Property Issuer, @{n=’ExpireInDays’;e={($_.notafter – (Get-Date)).Days}} -First 1

Thank you to @bruce-zhang

Upvotes: 0

Booga Roo
Booga Roo

Reputation: 1781

Since IIS certificates are your scope of concern here, I would suggest using the IIS PowerShell module to make sure you're selecting only certificates that are actually in use by IIS.

The following should pull certificates attached to sites with HTTPS(SSL). I don't currently have multiple sites on a single IIS server for testing, but theoretically this should find all of them, not just the "Default Web Site."

$serverlist = $serverListpath.Name
foreach($server in $serverlist){
    if($server -like '#*')
    {
        continue
    }

$threshold = 500   #Number of days to look for expiring certificates
$deadline = (Get-Date).AddDays($threshold)   #Set deadline date
$p = ($c++/$server.count) * 100
 Write-Progress -Activity "Checking $._" -Status "$p % completed" -PercentComplete $p;
 if(Test-Connection -ComputerName $server -Count 2 -Quiet){
 #$server = "KnownIISServerHostname" #<-- to test with a hostname
 #Pull certificates from existing IIS bindings
 $certificates = Invoke-Command -Verbose -ComputerName $server { 
    Import-Module IISAdministration
    $sitebindings = Get-IISSite | foreach { Get-IISSiteBinding -Protocol HTTPS -Name $_ }
    $thumbprints = $sitebindings.Attributes | where {$_.Name -match "certificateHash"} | Select-Object -ExpandProperty Value
    $thumbprints | foreach {dir Cert:\LocalMachine\My\$_}
    }
$certificates |`
foreach {
    If ($_.NotAfter -le $deadline) { 
    $_ | Select *| select PSComputerName, Subject, NotAfter, @{Label="Expires In (Days)";Expression={($_.NotAfter - (Get-Date)).Days}} }
}|`
select PSComputerName,Subject, NotAfter, @{Label="Expires In (Days)";Expression={($_.NotAfter - (Get-Date)).Days}} |`
export-csv -Force -Append -Encoding ASCII -NoTypeInformation .\output\$day-ExpiringIISSSLCerts.csv
}
}

Upvotes: 1

Bruce Zhang
Bruce Zhang

Reputation: 3042

Try to use this:

Import-Module WebAdministration
$CertAll=Get-ChildItem -Path Cert:\LocalMachine\My
$CertInUse=Get-Childitem -Path IIS:\SslBindings
$CertSame=Compare-Object -ReferenceObject $CertAll -DifferenceObject $CertInUse -Property ThumbPrint -IncludeEqual -ExcludeDifferent
$CertSame | foreach{Get-Childitem –path Cert:\LocalMachine\My\$($_.thumbprint)} | Select-Object -Property Subject, @{n=’ExpireInDays’;e={($_.notafter – (Get-Date)).Days}}

enter image description here

Upvotes: 1

Related Questions