Search code examples
powershellpowershell-4.0powershell-provider

Powershell "Provider execution stopped because the provider does not support this operation."


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 
                }           
         }    
     }
  }

Solution

  • 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)