Public/Get-CertificateStoreReport.ps1
|
function Get-CertificateStoreReport { <# .SYNOPSIS Produces a comprehensive inventory of certificates in a store. .DESCRIPTION Enumerates every certificate in the specified store on local or remote computers and returns detailed metadata including key length, signature algorithm, private key presence, and an expiry finding. By default expired certificates are excluded from output; use -IncludeExpired to include them. .PARAMETER ComputerName One or more computer names to scan. Accepts pipeline input. Defaults to localhost. .PARAMETER StoreName Certificate store to inventory. Valid values: My, Root, CA, TrustedPeople. Defaults to My. .PARAMETER StoreLocation Certificate store location. Valid values: LocalMachine, CurrentUser. Defaults to LocalMachine. .PARAMETER IncludeExpired When specified, includes certificates whose NotAfter date has passed. .EXAMPLE Get-CertificateStoreReport Inventories all non-expired certificates in LocalMachine\My on the local machine. .EXAMPLE Get-CertificateStoreReport -StoreName Root -IncludeExpired Inventories the Trusted Root CA store including expired certificates. .EXAMPLE Get-CertificateStoreReport -ComputerName DC01 -StoreName CA Inventories the Intermediate CA store on DC01. .OUTPUTS PSCustomObject with properties: Subject, Issuer, Thumbprint, NotBefore, NotAfter, DaysRemaining, KeyLength, SignatureAlgorithm, HasPrivateKey, Store, Finding. #> [CmdletBinding()] param( [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)] [string[]]$ComputerName = @('localhost'), [Parameter()] [ValidateSet('My', 'Root', 'CA', 'TrustedPeople')] [string]$StoreName = 'My', [Parameter()] [ValidateSet('LocalMachine', 'CurrentUser')] [string]$StoreLocation = 'LocalMachine', [Parameter()] [switch]$IncludeExpired ) begin { Write-Verbose "Get-CertificateStoreReport - $StoreLocation\$StoreName (IncludeExpired=$IncludeExpired)" $scriptBlock = { param($StoreName, $StoreLocation, $IncludeExpired) $storePath = "Cert:\$StoreLocation\$StoreName" if (-not (Test-Path $storePath)) { Write-Warning "Store $storePath does not exist on $env:COMPUTERNAME." return } $now = Get-Date Get-ChildItem -Path $storePath -ErrorAction SilentlyContinue | ForEach-Object { $cert = $_ $daysRemaining = ($cert.NotAfter - $now).Days # Skip expired unless requested if ($cert.NotAfter -lt $now -and -not $IncludeExpired) { return } $finding = if ($cert.NotAfter -lt $now) { 'EXPIRED' } elseif ($daysRemaining -le 7) { 'CRITICAL' } elseif ($daysRemaining -le 30) { 'WARNING' } else { 'OK' } # Extract key length from the public key $keyLength = 0 try { if ($cert.PublicKey.Key) { $keyLength = $cert.PublicKey.Key.KeySize } elseif ($cert.PublicKey.EncodedKeyValue) { $keyLength = $cert.PublicKey.EncodedKeyValue.RawData.Length * 8 } } catch { } # Signature algorithm friendly name $sigAlg = $cert.SignatureAlgorithm.FriendlyName [PSCustomObject]@{ Subject = $cert.Subject Issuer = $cert.Issuer Thumbprint = $cert.Thumbprint NotBefore = $cert.NotBefore NotAfter = $cert.NotAfter DaysRemaining = $daysRemaining KeyLength = $keyLength SignatureAlgorithm = $sigAlg HasPrivateKey = $cert.HasPrivateKey Store = "$StoreLocation\$StoreName" Finding = $finding } } } } process { foreach ($computer in $ComputerName) { Write-Verbose "Inventorying $StoreLocation\$StoreName on $computer" try { $isLocal = $computer -eq 'localhost' -or $computer -eq $env:COMPUTERNAME -or $computer -eq '.' if ($isLocal) { $results = & $scriptBlock -StoreName $StoreName ` -StoreLocation $StoreLocation ` -IncludeExpired $IncludeExpired.IsPresent } else { $results = Invoke-Command -ComputerName $computer ` -ScriptBlock $scriptBlock ` -ArgumentList $StoreName, $StoreLocation, $IncludeExpired.IsPresent ` -ErrorAction Stop } if ($results) { $results | ForEach-Object { $_ } } else { Write-Verbose "No certificates returned from $computer." } } catch { Write-Warning "Failed to inventory ${computer}: $_" } } } end { Write-Verbose 'Get-CertificateStoreReport complete.' } } |