157 lines
7.5 KiB
PowerShell
157 lines
7.5 KiB
PowerShell
|
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 <StoreLocation>
|
||
|
[string] Specifying the CurrentUser or LocalComputer when navigating Certificate locations
|
||
|
|
||
|
.PARAMETER <Store>
|
||
|
[string] Specifying the folder in which to search for a specific Certificate
|
||
|
|
||
|
.PARAMETER <FriendlyName>
|
||
|
[string] A descriptory text to distinguish different Certificates. Not always provided by the Certificate
|
||
|
|
||
|
.PARAMETER <Thumbprint>
|
||
|
[string] A specific code that singles out a Certificate
|
||
|
|
||
|
.PARAMETER <Certificate>
|
||
|
[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
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|