function Remove-Certificate { <# .SYNOPSIS Deletes a specified Certificate .DESCRIPTION This function helps locate a specific Certificate to delete based on where it is located and by a distinguishing characteristic. Otherwise a Certificate object can be inputted into the function to delete as well. For the function to work as intended, one of the three must be provided... FriendlyName [string] Thumbprint [string] Certificate [object] .PARAMETER [string] Specifying the CurrentUser or LocalComputer when navigating Certificate locations .PARAMETER [string] Specifying the folder in which to search for a specific Certificate .PARAMETER [string] A descriptory text to distinguish different Certificates. Not always provided by the Certificate .PARAMETER [string] A specific code that singles out a Certificate .PARAMETER [object] This is an item (certificate) that has already been selected to run this function against .EXAMPLE Remove-Certificate -Store TrustedPublisher -FriendlyName 'Alkami Issued Token' .EXAMPLE Get-Item 'Cert:\LocalMachine\TrustedPublisher\E7EAC1F158CB26C5D2B061B9085D65F7CCC4ADAC' | Remove-Certificate #> [CmdletBinding(DefaultParameterSetName = 'Certificate', SupportsShouldProcess = $true)] param ( [Parameter(Mandatory, ParameterSetName = "Certificate", ValueFromPipeline)] [object]$Certificate, [Parameter(ParameterSetName = "Thumbprint")] [string]$Thumbprint, [Parameter(ParameterSetName = "FriendlyName")] [string]$FriendlyName, [Parameter()] [ValidateSet('CurrentUser','LocalMachine')] [string]$StoreLocation = 'LocalMachine', [Parameter()] [ArgumentCompleter({ $possibleValues = @('My','TrustedPeople','CA','UserDS','Root','TrustedPublisher', 'AddressBook','Remote Desktop') return $possibleValues | ForEach-Object { $_ } # Runs through the foreach loop while the user is tabbing through the different fields })][string]$Store, [Parameter()] [switch]$Force ) $logLead = Get-LogLeadName # If the certificate is populated, and is not a string or is explicitly a certificate that data is used for input if ($null -ne $Certificate ) { $certType = $Certificate.GetType().Name if ($certType -eq "String") { Write-Error "$logLead : Certificate parameter was passed as an unrecognizable or unacceptable type: [$certType]. Exiting." throw New-Object System.ArgumentException "Certificate parameter is expected to be a certificate object." } if ($certType -ne "X509Certificate2") { Write-Warning "$logLead : Certificate is of type [$certType]. This is not explicitly an X509Certificate2, but it's not a string either. Proceeding." } $CertificatePSPath = $Certificate.PSPath if (![string]::IsNullOrWhiteSpace($CertificatePSPath)) { # Splitting the path to get the $Store and $StoreLocation $pathSplits = $Certificate.PSParentPath -split '::' if ($pathSplits[0] -eq "Microsoft.PowerShell.Security\Certificate") { $CertLocationAndStore = $pathSplits[1] -split "\\" # Overwriting user input with Certificate input for Store and StoreLocation $CertStoreLocation = $CertLocationAndStore[0] $CertStore = $CertLocationAndStore[1] if (![string]::IsNullOrWhiteSpace($StoreLocation)) { if ($CertStoreLocation -ne $StoreLocation) { Write-Warning "$logLead : The Certificate's Store Location [$CertStoreLocation] does not match the inputted Store Location [$StoreLocation]" Write-Warning "$logLead : Using the Certificate provided Store Location [$CertStoreLocation]" $StoreLocation = $CertStoreLocation } if (![string]::IsNullOrWhiteSpace($Store)) { if ($CertStore -ne $Store) { Write-Warning "$logLead : The Certificate's Store [$CertStore] does not match the inputted Store [$Store]" Write-Warning "$logLead : Using the Certificate provided Store [$CertStore]" $Store = $CertStore } } } } } $Thumbprint = $Certificate.Thumbprint } $certBasePath = (Join-Path (Join-Path "cert:\" $StoreLocation) $Store) # Testing to see if the $Store provided is an actual directory if (!(Test-Path $certBasePath)) { Write-Warning "$logLead : The specified store [$Store] does not exist on the store location [$StoreLocation]" Write-Warning "$logLead : No work to do, stopping" return } $certificates = @() if (![string]::IsNullOrWhiteSpace($Thumbprint)) { # Finding cert based on given Thumbprint $certificates = @(Get-ChildItem $certBasePath -Recurse | Where-Object { $_.Thumbprint -eq $Thumbprint}) if (Test-IsCollectionNullOrEmpty $certificates) { Write-Warning "$logLead : No certificate could be found with the thumbprint [$Thumbprint] in the specified store and location [$StoreLocation\$Store]" Write-Warning "$logLead : No work to do, stopping" return } } elseif(Test-StringIsNullOrWhiteSpace -value $FriendlyName) { $foundCertificates = @(Get-ChildItem $certBasePath -Recurse | Where-Object { $_.FriendlyName -eq $FriendlyName }) Write-Warning "$logLead : Received no thumbprint, and an empty string for FriendlyName. This has resulted in inadvertent mass certificate removal in the past." Write-Warning "$logLead : The following is the list of certificates which would be removed, along with their thumbprints." Write-Warning "$logLead : If you truly intended to remove these certificates, call this function with each thumbprint explicitly:" $foundCertificates return } else { # Finding cert based on given FriendlyName $certificates = @(Get-ChildItem $certBasePath -Recurse | Where-Object { $_.FriendlyName -eq $FriendlyName }) if (Test-IsCollectionNullOrEmpty $certificates) { Write-Warning "$logLead : No certificate could be found with the friendly name [$FriendlyName] in the specified store and location [$StoreLocation\$Store]" Write-Warning "$logLead : No work to do, stopping" return } } if ($Force -or $PSCmdlet.ShouldProcess("Do you want to delete [$($certificates.Count)] certificate(s) with thumbprint(s) [$($certificates.Thumbprint)] in store(s) [$($certificates.PSPath)]")) { foreach ($cert in $certificates) { # Checking to see if the Certificate has a Private Key if ($cert.HasPrivateKey -eq $true) { Write-Host "$logLead : Private Key Found" # Removal of Certification and Private Key Write-Host "$logLead : Removed $($Cert.PSPath) [$($cert.FriendlyName)] and corresponding Private Key" Remove-Item -Path $Cert.PSPath -DeleteKey -Force } else { # If there is no private key, continue to delete the Certificate Write-Host "$logLead : Private Key Not Found" Write-Host "$logLead : Removing $($Cert.PSPath) $($cert.FriendlyName)" Remove-Item -Path $Cert.PSPath -Force } } } }