Functions/CertificateManagement/Get-FpsCertificate.ps1
<#
.SYNOPSIS Returns all installed certificates that matches with the given ThumbPrint or SubjectFilter. .DESCRIPTION Default this cmdlet searches for certificates that have a private key. Enable IncludePublicCertificates to search for certificates with only a public key too. .EXAMPLE Get-FpsCertificate -ReturnCertObject .EXAMPLE Get-FpsCertificate -ThumbPrint '008CEE1FEA5RANDOM2AF4F603EBPRINTBB0341D1' .EXAMPLE Get-FpsCertificate -CertificatePath 'cert:\LocalMachine\WebHosting' -SubjectFilter 'MySubject*' -IncludePublicCertificates #> function Get-FpsCertificate { [CmdletBinding(DefaultParameterSetName='SearchWithSubjectFilter')] param( # The certificate unique thumbprint [Parameter(Mandatory=$true, ParameterSetName='SearchWithThumbPrint', ValueFromPipelineByPropertyName=$true, ValueFromPipeline=$true)] [ValidatePattern('^[a-zA-Z\d]+$')] [string] $ThumbPrint, # A subject filter to find certificates. E.g. 'MySubject*' returns all certificates where the subject starts with 'MySubject'. # Default value is: '*4ps*' [Parameter(ParameterSetName='SearchWithSubjectFilter', ValueFromPipelineByPropertyName=$true)] [string] $SubjectFilter = '*4ps*', # The certificate provider path where to scan for certificates. Path should start with 'Cert:'. E.g. 'cert:\LocalMachine\WebHosting'. # Default value is: 'cert:\LocalMachine\My' [Parameter(ValueFromPipelineByPropertyName=$true)] [string] $CertStorePath = 'cert:\LocalMachine\My', # When enabled this cmdlet returns the X509Certificate2 certificate object instead of a new powershell object. # Note: When enabled additional properties like UsedOnIISWebSites and UsedOnBcServerInstances are not added on the returned object anymore. [Parameter(ValueFromPipelineByPropertyName=$true)] [switch] $ReturnCertObject, # Enable IncludePublicCertificates to search for Public and Private installed certificates. [Parameter(ValueFromPipelineByPropertyName=$true)] [switch] $IncludePublicCertificates, [Parameter(ValueFromPipelineByPropertyName=$true)] [switch] $SkipScanWebsiteBindings, [Parameter(ValueFromPipelineByPropertyName=$true)] [switch] $SkipScanBcConfig ) # Test if the get-website cmdlet is available on the host. $SkipScanWebsiteBindings = if((Get-Command get-website -ErrorAction SilentlyContinue) -and $SkipScanWebsiteBindings -ne $true){ $false } else {$true} # Get the certificate based on either the thumprint or subjectfilter. if(-not [string]::IsNullOrEmpty($ThumbPrint)){ $certificates = Get-ChildItem -path $CertStorePath | Where-Object -Property Thumbprint -eq $ThumbPrint } else { $certificates = Get-ChildItem -path $CertStorePath | Where-Object subject -like $SubjectFilter } if(-not $IncludePublicCertificates){ $certificates = $certificates | Where-Object -Property HasPrivateKey -eq $true } # $certificates = $certificates | Where-Object -Property FriendlyName -ne '' if($ReturnCertObject){ return $certificates } if(!$SkipScanBcConfig){ $bcServerInstances = Get-BCServerInstance $bcServerInstances | ForEach-Object {$_.AppSettings = New-Object psobject -Property $_.AppSettings} # work-around: Convert hashtable to psobject } if(!$SkipScanWebsiteBindings){ $WebSites = Get-Website } foreach ($certificate in $certificates){ # Add IIS WebSite names to certificate object where the certificate is used in the https bindings if(!$SkipScanWebsiteBindings){ $WebSitesWithCertBinding = $WebSites | ForEach-Object { foreach ($binding in $_.bindings.Collection){ if($binding.protocol -eq 'https' -and $binding.certificateHash -eq $certificate.Thumbprint){ $_ } } } $certificate | Add-Member -NotePropertyName 'UsedOnIISWebSites' -NotePropertyValue $WebSitesWithCertBinding.Name } else { Write-Verbose 'Scan IIS website bindings is disabled.' } # Add Business Central ServerInstances names to certificate object where the certificate is used if(!$SkipScanBcConfig){ $certificate | Add-Member -NotePropertyName 'UsedOnBcServerInstances' -NotePropertyValue ` ($bcServerInstances | Where-Object {$_.AppSettings.ServicesCertificateThumbprint -eq $certificate.Thumbprint}).ServerInstance } else { Write-Verbose 'Scan Business Central ServerInstances is disabled.' } # Add users to certificate object with Read access on the certificate Write-Verbose 'Searching for users with read access on the certificate...' $certObj = Get-FpsCertificate -ThumbPrint $certificate.Thumbprint -CertStorePath $CertStorePath -ReturnCertObject if($certObj){ $certPath = '{0}\Microsoft\Crypto\RSA\MachineKeys\{1}' -f $env:ALLUSERSPROFILE, [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($certObj).key.UniqueName } else { $certPath = '' } Write-Verbose ('Certificate path for certificate ''{0}'': {1}' -f $certificate.Thumbprint, $certPath) if($certPath){ $certificate | Add-Member -NotePropertyName 'UsersWithReadAccess' -NotePropertyValue ` ((Get-Acl -Path $certPath).Access | Where-Object {$_.AccessControlType -eq 'Allow' -and $_.FileSystemRights -match 'FullControl|Read' -and $_.IdentityReference -notlike 'S-*'}).IdentityReference.Value } # Add expiration information to certificate object $certificate | Add-Member -NotePropertyName 'IsExpired' -NotePropertyValue ($certificate.NotAfter -lt (Get-Date)) $DaysToExpiration = ($certificate.NotAfter - (Get-Date)).Days if([double]$DaysToExpiration -lt 0){$DaysToExpiration = 0} $certificate | Add-Member -NotePropertyName 'DaysToExpiration' -NotePropertyValue $DaysToExpiration } # Converts X509Certificate2 to PSCustom objects and select most usefull properties return $certificates | Select-Object FriendlyName, Subject, Thumbprint, Issuer, HasPrivateKey, NotBefore, NotAfter, DaysToExpiration, IsExpired, UsedOnIISWebSites, UsedOnBcServerInstances, UsersWithReadAccess } Export-ModuleMember -Function Get-FpsCertificate |