Removing Certifiates using Powershell version 2 and denial, (Yeah I know)....

Hi guys,

I am working with a mixed environment where my customer has some older PowerShell version 2 installations.

I know that these should be updated to the lastest version of PS however due to the platform being rigorously controlled in regards to software upgrades etc. I unfortunately have to work with what I have.

I have written a script which caters for this and will (or should) remove a particular certificate from a number of servers based on a particular thumbprint variable, however when run I receive the following Access Denied error:

Exception calling “Remove” with “1” argument(s): "Access is denied.

I have read a few articles on this where they all mention running the powershell console or ISE as administrator, particularly when UAC is enabled, however I do not have UAC enabled on the host or destination machine and my account is a member of Domain Admins so this is really starting to annoy the hell out of me.

Any help would be much appreciated!

Code below:

[pre]

$FinalList = @()

$CurrentSystem = @()

$Machine = get-content Servers.txt

$Thumb = Get-Content Thumbprint.txt

foreach ($Server in $Machine)

{

Write-Host $Server

$CurrentSystem = Invoke-Command -computername $Server -ArgumentList $Thumb -scriptblock{

param($Thumb)

$Store = New-Object System.Security.Cryptography.x509Certificates.x509Store(“ROOT”,“LocalMachine”)

$Store.Open(“ReadWrite”)

#$Certificate = gci Cert:\LocalMachine\Root -Recurse | Where-Object {$_.Thumbprint -eq $Thumb}

$Certificate = $store.Certificates | Where {$_.Thumbprint -eq $Thumb}

$store.Remove($Certificate)

#$Certificate | Remove-Item

}

$finallist += $Server,$Thumb

}

$finallist | Out-File CertsDeleted.txt -Append

[/pre]

You should tinker around with the provider instead of trying to deal with the class the way you are doing it now.

PowerShell already has a build in provider dating at least back to 2.0. It makes the certificate behave like a directory tree structure. To see what I mean open PowerShell and change your location by typing cd Cert: from there you can do a dir and see that just like the GUI snapin for certificates there’s 2 folders there. The current user (My) or the local machine. Change directory into whichever one you need, then you can go into the next level down whether it be trusted root. You can even recursively search for your thumbprint that your current script is trying to work with.

In here I know for a fact you can delete so be very careful and practice with the -WhatIf switch to be sure.

-VERN

Appreciate your reply Vern,

yes I am aware of the PSProvider CERT: however unfortunately the remove-item cmdlet will only work with PS v.3 or above hence the reason why I am using the v.2.0 compatible lines 20,22 . 26 and 28 of code, replacing the otherwise hashed out lines of code which would otherwise work happily with the more recent PS versions.

My code should work however I cannot understand why I am getting the following:

 

Exception calling “Remove” with “1” argument(s): "Access is denied.

"

  • CategoryInfo : NotSpecified: (:slight_smile: [], MethodInvocationException

  • FullyQualifiedErrorId : DotNetMethodException

  • PSComputerName : <COMPUTERNAME>

Any takers to save me endless hours of manually deleting these old certs?

 

Thanks.

Can you try executing the content inside the ScriptBlock locally in in the server where its failing ?

Hi Kvprasoon, thanks very much for your input.

I did try this locally and unfortunately am receiving the same Access is denied message.

UAC is disabled, executionpolicy is unrestricted and the script is run as admin, system, I am unfortunately back to manually logging in and deleting the old certs by hand lol.

Nevermind, we are in the process of rolling out W2K12 and W2K16 servers so eventually we will upgrade to PSver4 and then I can simply use remove-item for the Cert: provider.

 

Thanks again.

Can you try MaxAllowed instead of ReadWrite permission.

Hi Kvprasoon, thanks very again for replying.
I have tried your suggestion however I am having problems with passing one of my values into my scriptblock using the param variable $Thumb.
Do you have any idea why it wont pass through as I am receiving the error 'Value cannot be null' ?
[pre]

param ($Thumb)

$Thumb = Get-Content Thumbprint.txt

$FinalList = @()

$CurrentSystem = @()

$Machine = get-content Servers.txt

foreach ($Server in $Machine)

{

Write-Host $Server

$CurrentSystem = Invoke-Command -scriptblock{

$Store = New-Object System.Security.Cryptography.x509Certificates.x509Store(“CA”,“LocalMachine”)

$Store.Open(“MaxAllowed”)

#$Certificate = gci Cert:\LocalMachine\Root -Recurse | Where-Object {$_.Thumbprint -eq $Thumb}

$Certificate = $store.Certificates | Where {$_.Thumbprint -eq $Thumb}

$store.Remove($Certificate)

$Store.Close()

$finallist += $Server,$Thumb

} -ArgumentList $Thumb

}

$finallist | Out-File CertsDeleted.txt -Append

[/pre]

Thanks.

Please post the code using code posting instruction or use gist.github.com and paste the link here.

There are few mistakes in the code you have posted.

  • You have defined $Thumb parameter in Param() block and the same variable is overwritten in the next line, which makes the parameter useless.
  • You are passing $Thumb using -ArgumentList, but there is no Param() block defined inside ScriptBlock to accept it.
  • The $FinalList variable is set inside the Invoke-Command and wont be available outside the scriptblock, this is defined and set in the remote machine. Return only the list and save it as the output of Invoke-Command.

Hi KVPrasoon many thanks for your help so far and apologies for my late reply,

I have re-written my code as I did paste it on the forum in my last post rather hastily, please find revised code below using what I hope to be the correct formatting.

Can you please assist me in how I should pass the $Thumb variable into my scriptblock as I am having difficulty in understanding how to do this in powershell?

[pre]

$Thumb = Get-Content Thumbprint.txt
$FinalList = @()
$CurrentSystem = @()
$Machine = get-content Servers.txt

foreach ($Server in $Machine)
{
Write-Host $Server

$CurrentSystem = Invoke-Command -scriptblock{
$Store = New-Object System.Security.Cryptography.x509Certificates.x509Store(“CA”,“LocalMachine”)
$Store.Open(“MaxAllowed”)
$Certificate = $store.Certificates | Where {$_.Thumbprint -eq $Thumb}
$store.Remove($Certificate)
$Store.Close()
} -ArgumentList $Thumb

$finallist += $Server,$Thumb

}

$finallist | Out-File CertsDeleted.txt -Append

[/pre]

 

many thanks.

This link will help you
https://devblogs.microsoft.com/powershell/how-to-pass-arguments-for-remote-commands/