0

I am trying to write a script to check a remote server for a certificate by FriendlyName. Once this is returned I want to confirm a removal of this cert. Currently the code below returns "Provider execution stopped because the provider does not support this operation." Why does the provider not work during the Remove-Item cmd but works earlier in the script when I use Select-Object?

$Logfile = "C:\Cert_Deletions_$(get-date -Format MMddyyyy).log"

Function LogWrite
{
   Param ([string]$logstring)

   Add-content $Logfile -value $logstring
}

#$TimeStamp = Get-Date;

LogWrite "Starting Cert Deletion Job $(get-date)";



$ContentsPath = 'C:\Servers.txt'
$Servers = "Server01"
$CertDeletionFile = 'C:\CertsDeleted.csv'
$Today = Get-Date

$typedCertificateName = Read-Host -Prompt "What certificate would you like 
to REMOVE?"

LogWrite "What Certificate would you like to REMOVE?"

function findCert {
param ([string]$Certificate)

Invoke-Command -ComputerName $Servers -ScriptBlock {

    Get-Childitem -Path  Cert:LocalMachine\My |
        where-Object {$_.friendlyname -eq $using:Certificate } |
        Select-Object -Property FriendlyName
    }
}
#line break
"`n"
Write-host "The following servers were found to hold the 
$typedCertificateName certificate:"
LogWrite "The following servers were found to hold the $typedCertificateName 
certificate:"
#line break
"`n"
$LocatedOn = findCert -Certificate $typedCertificateName
$LocatedOn
LogWrite $LocatedOn

"`n"

Write-host "Do you want to delete all certificates for $typedCertificateName 
??" -ForegroundColor Red 
LogWrite "Do you want to delete all certificates for $typedCertificateName 
??"
$Readhost = Read-Host " ( y / n ) " 
Switch ($ReadHost) 
 { 
   Y {Write-host "Yes, Deleting Now!!!" -ForegroundColor Yellow; 
       $Choice=$true} 
   N {Write-Host "No, Do NOT DELETE" -ForegroundColor Red; $Choice=$false} 
   Default {Write-Host "Default, Do Not Delete"; $Choice=$false} 
 } 

 If ($Readhost -eq 'y' -or 'Y') {
    Foreach ($Server in $Servers) {
        Invoke-Command -ComputerName $Server -ScriptBlock {
            try {
                Get-Childitem -Path  Cert:LocalMachine\My |
                where-Object {$_.friendlyname -eq 
$using:typedCertificateName} |
                Remove-Item  -ErrorAction Stop
                Write-host "$using:typedCertificateName has been deleted on 
$Server."
                #LogWrite "$using:typedCertificateName has been deleted on 
$Server."
                }
                catch
                {
                write-host $error 
                }           
         }    
     }
  }
Fixxer
  • 93
  • 1
  • 9
  • 1
    What line is giving the error? – Mike Shepard Jul 24 '18 at 21:40
  • 1
    It implies that you're using PowerShell 2. `Remove-Item` didn't work for the `cert:` provider until PowerShell 3. From the comments here - https://stackoverflow.com/a/37229338/478656 - and the documentation here - https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/providers/remove-item-for-certificate?view=powershell-6 . You have tagged this Powershell v4, but maybe your remote server is only on v2? – TessellatingHeckler Jul 24 '18 at 22:32
  • Run `Invoke-Command -Computername -Scriptblock {$PSVersionTable.psversion}` to check the remote servers powershell version – Drew Jul 25 '18 at 00:21
  • @TessellatingHeckler You were correct. Remote server is using PSv2. Local server is running PSv4. Thank you for the PSv2 script. I'm getting closer, but still need some help. I currently get the following error: VERBOSE: Open the certificate store [Cert:\LocalMachine\My]. VERBOSE: Open the certificate store [Cert:\LocalMachine\My] in [ReadWrite] VERBOSE: Get the list of certificates in the certificate store. VERBOSE: Discovered certificate with FriendlyName [*.me.com]. – Fixxer Jul 26 '18 at 05:05
  • Thank you to @Drew also. Return message continued from previous comment VERBOSE: Discovered certificate FriendlyName [*.me.com] does not match specified certificate friendlyname [cert.you.org]. VERBOSE: No 802.1x UniCERT certificates were discovered in the certificate store [Cert:\LocalMachine\My] on this machine. Skipping steps to verify that appropriate certificates were deleted. – Fixxer Jul 26 '18 at 05:06

1 Answers1

0

Here is an example of how to delete certificates on PowerShell v2 where the Remove-Item cmdlet doesn't work for certificate deletions. The script will first do the deletion and then verify that the deletion occurred. Feel free to modify for your purposes:

<#
.SYNOPSIS
    Removes all 802.1x certificates in the 'Cert:\LocalMachine\My' certificate store on a Windows machine which fit the defined criteria.
.DESCRIPTION
    Removes all 802.1x certificates in the 'Cert:\LocalMachine\My' certificate store with the following criteria:

    Certificate Issuer: Company Internal Sub CA
    Certificate Created with Template Name: Company-802.1x-mach-auth-AE-v1.0
    Certificate Store: LocalMachine\My
.EXAMPLE
    powershell.exe -File '.\Remove-DcmAll8021xUniCERT.ps1'
    Returns 'Not Compliant' if ANY certificates REMAIN in 'Cert:\LocalMachine\My' that fit the criteria described above AFTER the removal step is performed.
    Returns 'Compliant' if no such certs are found AFTER the removal step is performed.
.NOTES
#>

## Start by setting the execution policy for this PowerShell process
Try { Set-ExecutionPolicy -ExecutionPolicy 'ByPass' -Scope 'Process' -Force -ErrorAction 'Stop' } Catch { }

## VerbosePreference Options: Stop, Inquire, Continue, SilentlyContinue
#  Set to Continue to see all Write-Verbose output
$VerbosePreference = 'SilentlyContinue'

## WarningPreference Options: Stop, Inqurie, Continue, SilentlyContinue
#  Set to Continue to see all Write-Warning output
$WarningPreference = 'SilentlyContinue'

## Set DCM compliance status to default value of 'Compliant'
[string]$DCM_Compliance_Status = 'Compliant'

## Definite certificate properties we are looking for
[string]$CertStoreName = 'Cert:\LocalMachine\My'
[string]$TemplateName = 'Company-802.1x-mach-auth-AE-v1.0'
[string]$CertIssuer = 'Company Internal Sub CA'

Try {
    ## Open the specified certificate store
    [boolean]$IsCertStoreOpen = $false
    Write-Verbose -Message "Open the certificate store [$CertStoreName]."
    [System.Security.Cryptography.X509Certificates.X509Store]$MyLocalMachineCertStore = Get-Item -Path $CertStoreName -ErrorAction 'Stop'
    [boolean]$IsCertStoreOpen = $true

    ## Open the certificate store in Read/Write mode so that we can delete the matching certificates from it.
    Write-Verbose -Message "Open the certificate store [$CertStoreName] in [ReadWrite] mode."
    $MyLocalMachineCertStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)

    ## Get list of certificates in certificate store
    Write-Verbose -Message "Get the list of certificates in the certificate store."
    [System.Security.Cryptography.X509Certificates.X509Certificate2[]]$MyLocalMachineCertificates = $MyLocalMachineCertStore.Certificates

    ## Delete certificates that match specified issuer and if they were created using the specified certificate template
    ForEach ($Cert in $MyLocalMachineCertificates) {
        Try {
            Write-Verbose -Message '---------------------------------------------------------------'
            Write-Verbose -Message "Discovered certificate with thumbprint [$($Cert.Thumbprint)]."

            ## Check to see if certificate matches specified certificate issuer
            [boolean]$IsCertMatchesIssuer = ($Cert.Issuer -cmatch $CertIssuer)
            If ($IsCertMatchesIssuer) {
                Write-Verbose -Message "Discovered certificate issuer [$($Cert.Issuer)] matches specified certificate issuer [$CertIssuer]."
            }
            Else {
                Write-Verbose -Message "Discovered certificate issuer [$($Cert.Issuer)] does not match specified certificate issuer [$CertIssuer]."
                Continue
            }


            ## Check to see if certificate matches specified certificate template
            [boolean]$IsCertMatchesTemplate = $false
            ForEach ($Extension in $Cert.Extensions) {
                #  Only check Format(0) against the name of the specified template if Oid.FriendlyName indicates this certificate was built from a template
                If ($Extension.Oid.FriendlyName -match 'Template' ){
                    Write-Verbose -Message 'Discovered certificate was built from a template.'
                    If ($Extension.Format(0) -match $TemplateName) {
                        Write-Verbose -Message "Discovered certificate was built from specified template [$TemplateName]."
                        [boolean]$IsCertMatchesTemplate = $true
                        Break
                    }
                    Else {
                        Write-Verbose -Message "Discovered certificate was not built from specified template [$TemplateName]."
                    }
                }
                Else {
                    Write-Verbose -Message 'Discovered certificate was not built from a template.'
                }
            }

            ## Check to see if we found a certificate that matches the specified issuer and was built with the specified template
            If ($IsCertMatchesIssuer -and $IsCertMatchesTemplate) {
                Write-Verbose -Message "Discovered certificate matches the specified issuer [$CertIssuer] and was built with the specified template [$TemplateName]."

                Try {
                    ## Delete the discovered certificate
                    #  Note: Remove-Item cmdlet does not support the certificate provider so the .Remove() method must be used to delete the cert
                    Write-Verbose -Message "Delete the discovered certificate with thumbprint [$($Cert.Thumbprint)]."
                    $null = $MyLocalMachineCertStore.Remove($Cert)

                    Write-Verbose -Message "Save the deleted certificate with thumbprint [$($Cert.Thumbprint)] for the deletion verification stage of the script."

                    [string[]]$RemovedCertificateThumbprints += $Cert.Thumbprint
                }
                Catch {
                    Write-Warning -Message ('{0}' -f $_.Exception.Message)

                    #  If we failed to remove the certificate, then the DCM is 'Not Compliant'
                    [string]$DCM_Compliance_Status = 'Not Compliant'
                }
            }

            #  Reset the state of the X509Certificate2 object
            $null = $Cert.Reset()
        }
        Catch {
            Write-Warning -Message ('{0}' -f $_.Exception.Message)
            [string]$DCM_Compliance_Status = 'Not Compliant'
            Continue
        }
    }
}
Catch {
    Write-Warning -Message ('{0}' -f $_.Exception.Message)

    [string]$DCM_Compliance_Status = 'Not Compliant'
    Write-Output -InputObject ($DCM_Compliance_Status)
    Exit
}
Finally {
    Try {
        If ($MyLocalMachineCertificates) {
            $null = $MyLocalMachineCertificates.Reset()
        }
        If ($IsCertStoreOpen) {
            $null = $MyLocalMachineCertStore.Close()
        }
    }
    Catch { }
}

Write-Verbose -Message '_______________________________________________________________'
Write-Verbose -Message '_______________________________________________________________'

## Verify that the certificates we wanted to delete have been deleted from the certificate store by filtering for those matching the thumbprint of the deleted certificate
If ($RemovedCertificateThumbprints) {
    Write-Verbose -Message 'Certificates with the matching specified criteria were discovered on this machine. Executing steps to verify that matching certificates were deleted.'

    Try {
        ## Open the specified certificate store
        [boolean]$IsCertStoreOpen = $false
        Write-Verbose -Message "Open the certificate store [$CertStoreName]."
        [System.Security.Cryptography.X509Certificates.X509Store]$MyLocalMachineCertStore = Get-Item -Path $CertStoreName -ErrorAction 'Stop'
        [boolean]$IsCertStoreOpen = $true

        ## Open the certificate store in Ready Only mode so that we can verify if targeted certificates were deleted.
        Write-Verbose -Message "Open the certificate store [$CertStoreName] in [ReadOnly] mode."
        $MyLocalMachineCertStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly)

        ## Get list of certificates in certificate store
        Write-Verbose -Message "Get the list of certificates in the certificate store."
        [System.Security.Cryptography.X509Certificates.X509Certificate2[]]$MyLocalMachineCertificates = $MyLocalMachineCertStore.Certificates

        ## Verify that matching certificates were deleted from the certificate store
        ForEach ($RemovedCertThumbprint in $RemovedCertificateThumbprints) {
            Try {
                If ($MyLocalMachineCertificates.Thumbprint -contains $RemovedCertThumbprint) {
                    Write-Warning -Message "Certificate with thumbprint [$RemovedCertThumbprint] was not successfully deleted from certificate store [$CertStoreName]."
                    #  We failed to remove the certificate from the certificate store. The machine is not compliant.
                    [string]$DCM_Compliance_Status = 'Not Compliant'
                }
                Else {
                    Write-Verbose -Message "Certificate with thumbprint [$RemovedCertThumbprint] was successfully deleted from certificate store [$CertStoreName]."
                }
            }
            Catch {
                Write-Warning -Message ('{0}' -f $_.Exception.Message)
                [string]$DCM_Compliance_Status = 'Not Compliant'
                Continue
            }
        }
    }
    Catch {
        Write-Warning -Message ('{0}' -f $_.Exception.Message)
        [string]$DCM_Compliance_Status = 'Not Compliant'
    }
    Finally {
        Try {
            If ($MyLocalMachineCertificates) {
                $null = $MyLocalMachineCertificates.Reset()
            }
            If ($IsCertStoreOpen) {
                $null = $MyLocalMachineCertStore.Close()
            }
        }
        Catch { }
    }
}
Else {
    Write-Verbose -Message "No 802.1x UniCERT certificates were discovered in the certificate store [$CertStoreName] on this machine. Skipping steps to verify that appropriate certificates were deleted."
}


## Write out the compliance status
Write-Output -InputObject ($DCM_Compliance_Status)
user1367200
  • 300
  • 2
  • 14
  • It seems that [System.Security.Cryptography.X509Certificates.X509Store]$MyLocalMachineCertStore needs to be changed to match what I think are PKCS certs. So something like [System.Security.Cryptography.PKCS.????]$MyLocalMachineCertStore but I don't know what class to fill in. – Fixxer Jul 26 '18 at 05:36
  • https://msdn.microsoft.com/en-us/library/system.security.cryptography.pkcs(v=vs.110).aspx – user1367200 Jul 26 '18 at 20:02
  • The X509 store reference will remain the same. You need to figure out how to discover the PKCS cert you wish to delete from the x509 certificate store on the local machine. – user1367200 Jul 26 '18 at 20:08