Get-CertificateHealth.ps1
<#
.Synopsis Get certificates from the filesystem or certificate store and display their health for expiration, pending expiration, and deprecated signature algorithms. .DESCRIPTION Get certificates from the filesystem or certificate store and display their health for expiration, pending expiration, and deprecated signature algorithms. The function outputs custom objects that include basic certificate properties as well as the certificate's expiration date, how many days are left, and the name of the signature algorithm used to generate the certificate. Depending on the provided warning and critical algorithm parameters, a certificate will be marked as OK, Warning, or Critical. By default the script considers sha1RSA certificates to be warning (deprecated) since vendors are beginning to consider these certificates to use weak encryption. The md5 signature algorithm has already been designated as vulnerable and will be marked as critical. Microsoft already blocks these certificates. The certificate validity period is evaluated to determine if the certificate has expired (Critical) or will be expiring soon. Use the WarningDays and CriticalDays parameters to denote certificates with pending expiration. The certificate key size is also an indicator of health. Key sizes less than 1024 bits are no longer supported, and now it is recommended to use at least 2048 bits. Requires Get-CertificateFile function from module CertificateHealth to evaluate certificate files from the filesystem. .NOTES Created by: Jason Wasser @wasserja Modified: 10/12/2015 10:56:31 AM Changelog: Version 1.2 * Added key size health properties Version 1.1 * Added PowerShell 2.0 compatibility. Version 1.0 * Initial Release .PARAMETER Path Enter a path or paths containing certificates to be checked. .PARAMETER WarningDays Specify the amount of days before the certificate expiration should be in a warning state. .PARAMETER CriticalDays Specify the amount of days before the certificate expiration should be in a critical state. .PARAMETER ExcludedThumbprint Array of thumbprints of certificates that should be excluded from being checked. This would be used if there is a certificate that you wish to ignore from health checks. .PARAMETER WarningAlgorithm Array of algorithms that are deprecated. .PARAMETER CriticalAlgorithm Array of algorithms with known vulnerabilities. .PARAMETER CritialKeySize Certificates with key size less than this value will be considered critical. .PARAMETER WarningKeySize Certificates with key size less than this value and greater than the CriticalKeySize will be considered warning. .PARAMETER CertUtilPath Path to the certutil.exe. .PARAMETER CertificateFileType Array of certificate file types that need to be checked. .PARAMETER Recurse Recurse through subdirectories of specified path(s). .EXAMPLE Get-CertificateHealth Gets all the certificates in the local machine personal certificate store (cert:\LocalMachine\My) and shows their basic information and health. .EXAMPLE Get-CertificateHealth -Path C:\Website\Certificates Gets all the certificates in the c:\Website\Certificates folder and shows their basic information and health. .EXAMPLE Get-CertificateHealth -Path 'Cert:\LocalMachine\My','C:\SSL' -Recurse Gets all the certificates in the local machine personal certificate store (cert:\LocalMachine\My) and C:\SSL including subfolders and shows their basic information and health. .LINK https://gallery.technet.microsoft.com/scriptcenter/Certificate-Health-b646aeff #> #requires -Version 2.0 function Get-CertificateHealth { [CmdletBinding()] Param ( [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, Position=0)] [string[]]$Path = 'Cert:\LocalMachine\My', [int]$WarningDays = 60, [int]$CriticalDays = 30, [string[]]$ExcludedThumbprint,#=@('DF16240B462E80151BBCD7529D4C557A8CE1671C'), [string[]]$WarningAlgorithm=('sha1RSA'), [string[]]$CriticalAlgorithm=('md5RSA'), [int]$CriticalKeySize=1024, [int]$WarningKeySize=2048, [string]$CertUtilPath = 'C:\Windows\System32\certutil.exe', [string[]]$CertificateFileType = ('*.cer','*.crt','*.p7b'), [switch]$Recurse = $false ) Begin { } Process { #region Certificate Check foreach ($CertPath in $Path) { # Gather certificates from the $CertPath # If we are looking in the Certificate Providor - Cert:\ if ($CertPath -like 'cert:\*') { Write-Verbose "Getting certificates from $CertPath" $Certificates = Get-ChildItem -Path $CertPath -Recurse:([bool]$Recurse.IsPresent) -Exclude $ExcludedThumbprint } # Otherwise we need to use the certutil.exe to get certificate information. else { Write-Verbose "Getting certificates from $CertPath" $Certificates = Get-CertificateFile -Path $CertPath -CertificateFileType $CertificateFileType -Recurse:([bool]$Recurse.IsPresent) | Where-Object -FilterScript {$_.Thumbprint -notcontains $ExcludedThumbprint} } if ($Certificates) { #region Check individual certificate foreach ($Certificate in $Certificates) { # I first need to convert the properties so that I can use a similar process on either file or store certificates. if ($Certificate.PSPath) { if ($PSVersionTable.PSVersion.Major -lt 3) { $CertificateProperties = @{ FileName = $Certificate.PSPath Subject = $Certificate.Subject SignatureAlgorithm = $Certificate.SignatureAlgorithm.FriendlyName NotBefore = $Certificate.NotBefore NotAfter = $Certificate.NotAfter Days = ($Certificate.NotAfter - (Get-Date)).Days Thumbprint = $Certificate.Thumbprint KeySize = $Certificate.PublicKey.Key.KeySize } } else { $CertificateProperties = [ordered]@{ FileName = $Certificate.PSPath Subject = $Certificate.Subject SignatureAlgorithm = $Certificate.SignatureAlgorithm.FriendlyName NotBefore = $Certificate.NotBefore NotAfter = $Certificate.NotAfter Days = ($Certificate.NotAfter - (Get-Date)).Days Thumbprint = $Certificate.Thumbprint KeySize = $Certificate.PublicKey.Key.KeySize } } $Certificate = New-Object -TypeName PSObject -Property $CertificateProperties } elseif ($Certificate.FileName) { # Nothing to do here yet. } else { # Nothing to do here yet. } #region Check certificate expiration # Check certificate is within $WarningDays if ($Certificate.NotAfter -le (Get-Date).AddDays($WarningDays) -and $Certificate.NotAfter -gt (Get-Date).AddDays($CriticalDays)) { Write-Verbose "Certificate is expiring within $WarningDays days." $ValidityPeriodStatus = 'Warning' $ValidityPeriodStatusMessage = "Certificate expiring in $($Certificate.Days) days." } # Check certificate is within $CriticalDays elseif ($Certificate.NotAfter -le (Get-Date).AddDays($CriticalDays) -and $Certificate.NotAfter -gt (Get-Date)) { Write-Verbose "Certificate is expiring within $CriticalDays days." $ValidityPeriodStatus = 'Critical' $ValidityPeriodStatusMessage = "Certificate expiring in $($Certificate.Days) days." } # Check certificate is expired elseif ($Certificate.NotAfter -le (Get-Date)) { Write-Verbose "Certificate is expiring within $CriticalDays" $ValidityPeriodStatus = 'Critical' $ValidityPeriodStatusMessage = "Certificate expired: $($Certificate.Days) days." } # Certificate validity period is healthy. else { Write-Verbose "Certificate is within validity period." $ValidityPeriodStatus = 'OK' $ValidityPeriodStatusMessage = "Certificate expires in $($Certificate.Days) days." } #endregion #region Check certificate algorithm if ($CriticalAlgorithm -contains $Certificate.SignatureAlgorithm) { Write-Verbose "Certificate uses critical algorithm." $AlgorithmStatus = 'Critical' $AlgorithmStatusMessage = "Certificate uses a vulnerable algorithm $($Certificate.SignatureAlgorithm)." } elseif ($WarningAlgorithm -contains $Certificate.SignatureAlgorithm) { Write-Verbose "Certificate uses warning algorithm." $AlgorithmStatus = 'Warning' $AlgorithmStatusMessage = "Certificate uses the deprecated algorithm $($Certificate.SignatureAlgorithm)." } else { Write-Verbose "Certificate uses acceptable algorithm." $AlgorithmStatus = 'OK' $AlgorithmStatusMessage = "Certificate uses valid algorithm $($Certificate.SignatureAlgorithm)." } #endregion #region Check MinimumKeySize Write-Verbose 'Checking minimum key length.' if ($Certificate.KeySize -lt $CriticalKeySize) { # Key Size is critical Write-Verbose 'Certificate key length is critical.' $KeySizeStatus = 'Critical' $KeySizeStatusMessage = "Certificate key size $($Certificate.KeySize) is less than $CriticalKeySize." } elseif ($Certificate.KeySize -lt $WarningKeySize -and $Certificate.KeySize -ge $CriticalKeySize) { # Key Size is warning Write-Verbose 'Certificate key length is warning.' $KeySizeStatus = 'Warning' $KeySizeStatusMessage = "Certificate key size $($Certificate.KeySize) is less than $WarningKeySize." } elseif ($Certificate.KeySize -ge $WarningKeySize) { # Key Size is OK Write-Verbose 'Certificate key length is OK.' $KeySizeStatus = 'OK' $KeySizeStatusMessage = "Certificate key size $($Certificate.KeySize) is greater than or equal to $WarningKeySize." } else { # Key Size is OK Write-Verbose 'Certificate key length is Unknown.' $KeySizeStatus = 'Unknown' $KeySizeStatusMessage = "Certificate key size is unknown." } #endregion Write-Verbose 'Adding additional properties to the certificate object.' if ($PSVersionTable.PSVersion.Major -lt 3) { $CertificateProperties = @{ FileName = $Certificate.Filename Subject = $Certificate.Subject SignatureAlgorithm = $Certificate.SignatureAlgorithm NotBefore = $Certificate.NotBefore NotAfter = $Certificate.NotAfter Days = $Certificate.Days Thumbprint = $Certificate.Thumbprint ValidityPeriodStatus = $ValidityPeriodStatus ValidityPeriodStatusMessage = $ValidityPeriodStatusMessage AlgorithmStatus = $AlgorithmStatus AlgorithmStatusMessage = $AlgorithmStatusMessage KeySize = $Certificate.KeySize KeySizeStatus = $KeySizeStatus KeySizeStatusMessage = $KeySizeStatusMessage } } else { $CertificateProperties = [ordered]@{ FileName = $Certificate.Filename Subject = $Certificate.Subject SignatureAlgorithm = $Certificate.SignatureAlgorithm NotBefore = $Certificate.NotBefore NotAfter = $Certificate.NotAfter Days = $Certificate.Days Thumbprint = $Certificate.Thumbprint ValidityPeriodStatus = $ValidityPeriodStatus ValidityPeriodStatusMessage = $ValidityPeriodStatusMessage AlgorithmStatus = $AlgorithmStatus AlgorithmStatusMessage = $AlgorithmStatusMessage KeySize = $Certificate.KeySize KeySizeStatus = $KeySizeStatus KeySizeStatusMessage = $KeySizeStatusMessage } } $Certificate = New-Object -TypeName PSObject -Property $CertificateProperties if ($PSVersionTable.PSVersion.Major -lt 3) { $Certificate | Select-Object FileName,Subject,SignatureAlgorithm,NotBefore,NotAfter,Days,Thumbprint,ValidityPeriodStatus,ValidityPeriodStatusMessage,AlgorithmStatus,AlgorithmStatusMessage,KeySize,KeySizeStatus,KeySizeStatusMessage } else { $Certificate } } #endregion } else { Write-Verbose "No Certificates found in $CertPath" } } #endregion } End { } } |