Forum Discussion

jhipes's avatar
2 years ago
Solved

Pulling SSL certs from a local Certificate store

I am wondering if any one has been able to pull SSL certificate info from a servers local computer certificate store. I can get on the server and run the below PowerShell command and it pulls all of the SSL certificates that i expect. When i create a custom datasource to run this same PowerShell command its only pulling the SSL certificates for my local session.

Get-item Cert:\LocalMachine\my\* | select-object certificatedomains,issuer,status,notbefore,subject

I can run this command without admin rights, i am suspecting that Logic Monitor is using WMI to run this and for some reason it isnt allow of some sort.  I have searched all of the docs and cannot find anything on how to do this. Any help is greatly appreciated.

  • I created a module for this some time back -- should be in the Exchange.  I just looked at ours, though, and it is marked ‘Security Review’ which is super annoying since it was submitted 2 years ago at least -- LM has no apparent workflow for the Exchange, just have to find the right person to poke (if you get lucky). There should at least be some sort of “escalate” button on those to get someone’s attention.

    I also don’t think the version posted is our current version (we added some code later to avoid expired certs in some cases).  Here is the full source code (AD and collection).  Somewhat ironically, the code handler for the forum post editor does not include “PowerShell”.

    $TargetHostName = '##SYSTEM.SYSNAME##'
    $CollectorHostName = $env:computername
    $TargetUserName = '##wmi.user##'
    $TargetPassword = '##wmi.pass##'
    $DebugMode = $false


    $ScriptBlock = {
    param (
    [bool]$Debug
    )

    # Certificates need to have a lifespan of at least this number of days to be considered.
    $MinLifeSpan = 30

    # Certificates that are expired by more than this many days are ignored.
    $MaxExpired = 60

    $AllCerts = @()
    $CertExpire = @{}


    $CertList = Get-ChildItem -Path cert:LocalMachine -Recurse -SSLServerAuthentication
    Foreach ($Cert in $CertList) {
    $SerialNumber = $Cert.SerialNumber
    $FriendlyName = $Cert.FriendlyName;
    $Name = ""
    if ($FriendlyName -eq "")
    {
    $Name = $SerialNumber
    }
    else
    {
    $Name = "$FriendlyName - $SerialNumber"
    }

    $NotBefore = $Cert.NotBefore
    $NotAfter = $Cert.NotAfter
    $LifeSpan = New-TimeSpan -Start $NotBefore -End $NotAfter
    $LifeSpanDays = $LifeSpan.Days

    $Expired = New-TimeSpan -Start $NotAfter -End (Get-Date)
    $ExpiredDays = $Expired.Days

    if (($SerialNumber -ne "") -AND ($LifeSpanDays -gt $MinLifeSpan) -AND ($ExpiredDays -lt $MaxExpired)) {
    $Props = @()
    $propPrefix = "auto.windowscerts"
    $Props += "${propPrefix}.serialnum=$SerialNumber"
    $Store = ($Cert.PSParentPath -split "::")[1]
    #
    # Add this store to the cert expiration tracking hashtable if it isn't
    # there already
    #
    if ( -not $CertExpire.ContainsKey($Store) ){
    $CertExpire[$Store] = @{}
    }

    $Props += "${propPrefix}.lifespan_days=$LifeSpanDays"

    if ($Store -ne "") { $Props += "${propPrefix}.store=$Store" }
    if ($NotBefore -ne "") { $Props += "${propPrefix}.starts=$NotBefore" }
    if ($NotAfter -ne "") { $Props += "${propPrefix}.expires=$NotAfter" }
    $Subject = $Cert.Subject
    if ($Subject -ne "") { $Props += "${propPrefix}.subject=$Subject" }
    $Issuer = $Cert.Issuer
    if ($Issuer -ne "") { $Props += "${propPrefix}.issuer=$Issuer" }
    $Thumbprint = $Cert.Thumbprint
    if ($Thumbprint -ne "") { $Props += "${propPrefix}.thumbprint=$Thumbprint" }
    $DNSNameList = $Cert.DNSNameList
    if ($DNSNameList -ne "") { $Props += "${propPrefix}.dnsnames=$DNSNameList" }

    # If $ExpiredDays is negative it means the cert has not expired yet.
    # We care about all non-expired certs but only the most recent of expired certs with
    # the same CN in the same store
    $AllCerts += @{
    Subject = $Subject
    Store = $Store
    Name = $Name
    SerialNumber = $SerialNumber
    ExpiredDays = $ExpiredDays
    Props = $Props
    }

    if ( $CertExpire[$Store].ContainsKey($Subject) ){
    if ( $ExpiredDays -lt $CertExpire[$Store][$Subject] ){
    $CertExpire[$Store][$Subject] = $ExpiredDays
    }
    }
    else {
    $CertExpire[$Store][$Subject] = $ExpiredDays
    }

    # Write-Host "$SerialNumber##$Name##$Subject####", ($Props -join '&')
    }
    }
    foreach ( $Cert in $AllCerts ){
    $Subject = $Cert.Subject
    $Store = $Cert.Store
    $ExpiredDays = $Cert.ExpiredDays


    if ( ($ExpiredDays -gt 0) -AND ($ExpiredDays -gt $CertExpire[$Store][$Subject]) ){
    # Don't care about expired certs when a newer one exists in the same store
    # with the same Subject
    continue
    }

    $SerialNumber = $Cert.SerialNumber
    $Name = $Cert.Name
    $Props = $Cert.Props

    Write-Host "$SerialNumber##$Name##$Subject####", ($Props -join '&')
    }
    }

    if ($TargetHostName -eq $CollectorHostName)
    {
    Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList @($DebugMode)
    }
    else
    {
    #If WMI creds undefined - invoke remote command without creds, if not - create credential object and use it for authorization
    if (($TargetUserName -Match "wmi.user" -and $TargetPassword -Match "wmi.pass") -or
    ($TargetUserName -eq "" -and $TargetPassword -eq ""))
    {
    Invoke-Command -ComputerName $TargetHostName -ScriptBlock $ScriptBlock -ArgumentList @($DebugMode)
    }
    else
    {
    $TargetCredentials = New-Object System.Management.Automation.PSCredential ($TargetUserName, $(ConvertTo-SecureString $TargetPassword -AsPlainText -Force))
    Invoke-Command -ComputerName $TargetHostName -ScriptBlock $ScriptBlock -Credential $TargetCredentials -ArgumentList @($DebugMode)
    }
    }

    Exit 0
    $Instance = '##WILDVALUE##'
    $TargetHostName = '##SYSTEM.SYSNAME##'
    $CollectorHostName = $env:computername
    $TargetUserName = '##wmi.user##'
    $TargetPassword = '##wmi.pass##'
    $DebugMode = $false

    $ScriptBlock = {
    param (
    [bool]$Debug,
    [String]$SerialNumber
    )

    if ($Cert = Get-ChildItem -Path cert:LocalMachine -Recurse | Where-Object { $_.SerialNumber -eq $SerialNumber }) {
    # NotAfter can return multiple values, we'll just take the first (zeroth) one using [0]
    $TimeSpan = New-TimeSpan -Start (Get-Date) -End $Cert.NotAfter[0]
    $DaysLeft = $TimeSpan.Days
    Write-Host "DaysLeft=$DaysLeft"
    }
    }

    if ($TargetHostName -eq $CollectorHostName)
    {
    Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList @($DebugMode,$Instance)
    }
    else
    {
    #If WMI creds undefined - invoke remote command without creds, if not - create credential object and use it for authorization
    if (($TargetUserName -Match "wmi.user" -and $TargetPassword -Match "wmi.pass") -or
    ($TargetUserName -eq "" -and $TargetPassword -eq ""))
    {
    Invoke-Command -ComputerName $TargetHostName -ScriptBlock $ScriptBlock -ArgumentList @($DebugMode,$Instance)
    }
    else
    {
    $TargetCredentials = New-Object System.Management.Automation.PSCredential ($TargetUserName, $(ConvertTo-SecureString $TargetPassword -AsPlainText -Force))
    Invoke-Command -ComputerName $TargetHostName -ScriptBlock $ScriptBlock -Credential $TargetCredentials -ArgumentList @($DebugMode,$Instance)
    }
    }

    Exit 0

4 Replies

  • I created a module for this some time back -- should be in the Exchange.  I just looked at ours, though, and it is marked ‘Security Review’ which is super annoying since it was submitted 2 years ago at least -- LM has no apparent workflow for the Exchange, just have to find the right person to poke (if you get lucky). There should at least be some sort of “escalate” button on those to get someone’s attention.

    I also don’t think the version posted is our current version (we added some code later to avoid expired certs in some cases).  Here is the full source code (AD and collection).  Somewhat ironically, the code handler for the forum post editor does not include “PowerShell”.

    $TargetHostName = '##SYSTEM.SYSNAME##'
    $CollectorHostName = $env:computername
    $TargetUserName = '##wmi.user##'
    $TargetPassword = '##wmi.pass##'
    $DebugMode = $false


    $ScriptBlock = {
    param (
    [bool]$Debug
    )

    # Certificates need to have a lifespan of at least this number of days to be considered.
    $MinLifeSpan = 30

    # Certificates that are expired by more than this many days are ignored.
    $MaxExpired = 60

    $AllCerts = @()
    $CertExpire = @{}


    $CertList = Get-ChildItem -Path cert:LocalMachine -Recurse -SSLServerAuthentication
    Foreach ($Cert in $CertList) {
    $SerialNumber = $Cert.SerialNumber
    $FriendlyName = $Cert.FriendlyName;
    $Name = ""
    if ($FriendlyName -eq "")
    {
    $Name = $SerialNumber
    }
    else
    {
    $Name = "$FriendlyName - $SerialNumber"
    }

    $NotBefore = $Cert.NotBefore
    $NotAfter = $Cert.NotAfter
    $LifeSpan = New-TimeSpan -Start $NotBefore -End $NotAfter
    $LifeSpanDays = $LifeSpan.Days

    $Expired = New-TimeSpan -Start $NotAfter -End (Get-Date)
    $ExpiredDays = $Expired.Days

    if (($SerialNumber -ne "") -AND ($LifeSpanDays -gt $MinLifeSpan) -AND ($ExpiredDays -lt $MaxExpired)) {
    $Props = @()
    $propPrefix = "auto.windowscerts"
    $Props += "${propPrefix}.serialnum=$SerialNumber"
    $Store = ($Cert.PSParentPath -split "::")[1]
    #
    # Add this store to the cert expiration tracking hashtable if it isn't
    # there already
    #
    if ( -not $CertExpire.ContainsKey($Store) ){
    $CertExpire[$Store] = @{}
    }

    $Props += "${propPrefix}.lifespan_days=$LifeSpanDays"

    if ($Store -ne "") { $Props += "${propPrefix}.store=$Store" }
    if ($NotBefore -ne "") { $Props += "${propPrefix}.starts=$NotBefore" }
    if ($NotAfter -ne "") { $Props += "${propPrefix}.expires=$NotAfter" }
    $Subject = $Cert.Subject
    if ($Subject -ne "") { $Props += "${propPrefix}.subject=$Subject" }
    $Issuer = $Cert.Issuer
    if ($Issuer -ne "") { $Props += "${propPrefix}.issuer=$Issuer" }
    $Thumbprint = $Cert.Thumbprint
    if ($Thumbprint -ne "") { $Props += "${propPrefix}.thumbprint=$Thumbprint" }
    $DNSNameList = $Cert.DNSNameList
    if ($DNSNameList -ne "") { $Props += "${propPrefix}.dnsnames=$DNSNameList" }

    # If $ExpiredDays is negative it means the cert has not expired yet.
    # We care about all non-expired certs but only the most recent of expired certs with
    # the same CN in the same store
    $AllCerts += @{
    Subject = $Subject
    Store = $Store
    Name = $Name
    SerialNumber = $SerialNumber
    ExpiredDays = $ExpiredDays
    Props = $Props
    }

    if ( $CertExpire[$Store].ContainsKey($Subject) ){
    if ( $ExpiredDays -lt $CertExpire[$Store][$Subject] ){
    $CertExpire[$Store][$Subject] = $ExpiredDays
    }
    }
    else {
    $CertExpire[$Store][$Subject] = $ExpiredDays
    }

    # Write-Host "$SerialNumber##$Name##$Subject####", ($Props -join '&')
    }
    }
    foreach ( $Cert in $AllCerts ){
    $Subject = $Cert.Subject
    $Store = $Cert.Store
    $ExpiredDays = $Cert.ExpiredDays


    if ( ($ExpiredDays -gt 0) -AND ($ExpiredDays -gt $CertExpire[$Store][$Subject]) ){
    # Don't care about expired certs when a newer one exists in the same store
    # with the same Subject
    continue
    }

    $SerialNumber = $Cert.SerialNumber
    $Name = $Cert.Name
    $Props = $Cert.Props

    Write-Host "$SerialNumber##$Name##$Subject####", ($Props -join '&')
    }
    }

    if ($TargetHostName -eq $CollectorHostName)
    {
    Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList @($DebugMode)
    }
    else
    {
    #If WMI creds undefined - invoke remote command without creds, if not - create credential object and use it for authorization
    if (($TargetUserName -Match "wmi.user" -and $TargetPassword -Match "wmi.pass") -or
    ($TargetUserName -eq "" -and $TargetPassword -eq ""))
    {
    Invoke-Command -ComputerName $TargetHostName -ScriptBlock $ScriptBlock -ArgumentList @($DebugMode)
    }
    else
    {
    $TargetCredentials = New-Object System.Management.Automation.PSCredential ($TargetUserName, $(ConvertTo-SecureString $TargetPassword -AsPlainText -Force))
    Invoke-Command -ComputerName $TargetHostName -ScriptBlock $ScriptBlock -Credential $TargetCredentials -ArgumentList @($DebugMode)
    }
    }

    Exit 0
    $Instance = '##WILDVALUE##'
    $TargetHostName = '##SYSTEM.SYSNAME##'
    $CollectorHostName = $env:computername
    $TargetUserName = '##wmi.user##'
    $TargetPassword = '##wmi.pass##'
    $DebugMode = $false

    $ScriptBlock = {
    param (
    [bool]$Debug,
    [String]$SerialNumber
    )

    if ($Cert = Get-ChildItem -Path cert:LocalMachine -Recurse | Where-Object { $_.SerialNumber -eq $SerialNumber }) {
    # NotAfter can return multiple values, we'll just take the first (zeroth) one using [0]
    $TimeSpan = New-TimeSpan -Start (Get-Date) -End $Cert.NotAfter[0]
    $DaysLeft = $TimeSpan.Days
    Write-Host "DaysLeft=$DaysLeft"
    }
    }

    if ($TargetHostName -eq $CollectorHostName)
    {
    Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList @($DebugMode,$Instance)
    }
    else
    {
    #If WMI creds undefined - invoke remote command without creds, if not - create credential object and use it for authorization
    if (($TargetUserName -Match "wmi.user" -and $TargetPassword -Match "wmi.pass") -or
    ($TargetUserName -eq "" -and $TargetPassword -eq ""))
    {
    Invoke-Command -ComputerName $TargetHostName -ScriptBlock $ScriptBlock -ArgumentList @($DebugMode,$Instance)
    }
    else
    {
    $TargetCredentials = New-Object System.Management.Automation.PSCredential ($TargetUserName, $(ConvertTo-SecureString $TargetPassword -AsPlainText -Force))
    Invoke-Command -ComputerName $TargetHostName -ScriptBlock $ScriptBlock -Credential $TargetCredentials -ArgumentList @($DebugMode,$Instance)
    }
    }

    Exit 0
  • DataSource code always runs directly on the collector’s server, and it’s up to your code to connect to the relevant server with the SSL cert, unless you want to check the server the collector software is installed on. Might that be part of the issue?

  • This is fantastic, I am going to give this a try. I really appreciate the help.