Removing a certificate from the local machine certificate store in powershell? - powershell

I am trying to check for, and then remove a certificate if it exists in a user's local machine store. I've tried this:
$certCN = 'test.domain.com'
Set-Location Cert:\LocalMachine\My
$oldCert = Get-ChildItem -Recurse |
Where-Object { $_.subject -like "CN=$oldCert*" }
Remove-Item Cert:\LocalMachine\My\$oldCert -Force
But it is not removing the cert from the store or giving any errors (yes I am running this elevated).
I checked my $oldCert variable to see if it is populated and it is:
PS Cert:\LocalMachine\My> $oldcert
PSParentPath: Microsoft.PowerShell.Security\Certificate::LocalMachine\My
Thumbprint Subject
---------- -------
276B7B87740D5E9595A258060F5CD9CC4190E9E1 CN=test.domain.com, <truncated>
Does anyone know how to accomplish this? I really appreciate it.

The problem you're encountering is the automatic string conversion of the X509Certificate2 object from the Cert:\ drive. When you're appending it to your path as -Path some\path\$myobj, it's implicitly calling ToString on the object. You can observe this by doing "some\path\$myobj" at the console without any other code or by simply calling $myobj.ToString().
Because Remove-Item takes pipeline input by property name, it will automatically pull the path off your object when you pass it over the pipeline, so you can remediate your problem simply as such:
$oldCert | Remove-Item
or
Remove-Item -LiteralPath $oldCert.PSPath

Related

Using PDQ to Automate PowerShell or CMD to find and delete registry entries

We recently started using PDQ inventory and Deploy. We have some user endpoints that have corrupted agents from a different program. The fix for this corruption includes finding and deleting a registry key pertaining to that file. I am able to use both CMD and PowerShell in PDQ as steps to automate this process. I'm kind of at a loss since the registry value is different per asset.
How can I automate the function of finding the registry key and then deleting the registry key it finds?
So far I've tied the following command to a variable:
$RegKey = Get-ChildItem -Path HKLM:\SOFTWARE\Classes\Installer\Products -Recurse |
ForEach-Object { Get-ItemProperty $_.PSPath } |
Where-Object { $_ -like "*Rapid7 Insight Agent*" } |
Select-Object PSPath
Similarly, in CMD the manual commands are:
reg query HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Products\ /f "Rapid7 Insight Agent" /s
Reg Delete (with the value the previous reg query posts back)
Every provider that supports the Get-ChildItem cmdlet, also supports the Remove-Item cmdlet:
Get-ChildItem "HKLM:\SOFTWARE\Classes\Installer\Products" -Recurse |
Where-Object { $_.PSChildName -like "*Rapid7 Insight Agent*" } |
Remove-Item -Recurse

Select-Object output Directory path to Variable

I have a program that I need to uninstall on a number of systems and unfortunately the way this software is silently uninstalled is by running an exe called "uninstall.exe" this could be in 1 of many directories per system so I have a PowerShell script I'm trying to make work where I look for "Uninstall.exe" in any of the directories it may be located with:
get-childitem -recurse -include "uninstall.exe" 'C:\Program Files (x86)\mainoffice-*'
This seems to work as the output gives me the full path of the folder where "Uninstall.exe" is located. I will need to then run:
uninstall.exe --mode unattended
So I think I will need to output the full path where "Uninstall.exe" is located to a variable. I tired to do this with:
$uninstalldir = get-childitem -recurse -include "uninstall.exe" 'C:\Program Files (x86)\wwworksmainoffice-*' | Select-Object FullName
I can't seem to just get this to output the directory path so I can do something like:
$uninstalldir --mode unattended
Can anyone try help me understand where I might be going wrong here?
This pipeline:
... |Select-Object FullName
... will create a new object with a single property FullName, so in order to resolve just the string value stored in FullName you'd need to dereference it like this:
$uninstalldir.FullName
This is still just a value expression - it you want PowerShell to invoke a string as if it were a command or program, you'll need the & call operator:
& $uninstalldir.FullName --mode unattended
Alternatively, you could've used Select-Object -ExpandProperty FullName or ForEach-Object FullName to get just the raw value of the FullName property instead of sticthing it onto a new object:
$uninstalldir = Get-ChildItem ... |Select-Object -ExpandProperty FullName
# or
$uninstalldir = Get-ChildItem ... |ForEach-Object -MemberName FullName
At which point the variable itself resolves to the string value:
& $uninstalldir --mode unattended

Azure Devops - PowerShell task on self-hosted agent

I have an Azure Devops deployment pipeline setup which is building and I am able to deploy to a self hosted virtual machine with no issue.
I have the following powershell script that correctly clears down my destination directory leaving 2 folders that are not part of source control
Get-ChildItem -Path 'C:\inetpub\wwwroot\testDeploy\' -Recurse -exclude "pod","photos" |
Select -ExpandProperty FullName |
Where {$_ -notlike '*\pod\*' -and $_ -notlike '*\photos\*'} |
sort length -Descending |
Remove-Item -force
I have tried adding a "PowerShell Script" task but i'm don;t know how to get the PowerShell script in to a folder that the task can access i.e. $(System.DefaultWorkingDirectory). Can anyone advise how I should be either generating the file or where to store it in my repo that is then accessible by the self-hosted Windows agent
Agree with Shayki, you can create a powershell(.ps1) file in repos and paste your script in it to achieve that. And then, use powershell task to execute the script which in ps1 file.
But, as you said that you want it be maintained within the repos easily. Need made some change on your script:
Param(
[string]$RootPath,
[string]$File1,
[string]$File2,
[string]$NonLike1,
[string]$NonLike2
)
Get-ChildItem -Path $RootPath -Recurse -include $File1,$File2 |
Select -ExpandProperty FullName |
Where {$_ -notlike $NonLike1 -and $_ -notlike $NonLike2} |
sort length -Descending |
Remove-Item -Recurse -force
The first change is, you need to replace the hard code with variable. Pass the value with task, this is a good way to maintain your script.
The second which also the important change is add -Recurse after Remove-Item, or you will get the error showed below while the value of $RootPath is hard code, such as 'C:\Users\'.
Remove-Item : Windows PowerShell is in NonInteractive mode. Read and
Prompt functionality is not available.
And then, you can add task in your build pipeline. Add the Script path where the .ps1 file located and input the Arguments with the value:
If you want to access $(System.DefaultWorkingDirectory), pass it to $RootPath.
Hope my sample can help you achieve what you want.

How to find and delete previously created certificates based on their dns name using powershell?

I can create a self signed certificate with PowerShell:
$cert = New-SelfSignedCertificate –DnsName www.test.com -CertStoreLocation “cert:\LocalMachine\My”
Because this is an automated test scenario, I must allow multiple runs. Next time I (which is a completely separate session) would like to find all certificates with dns name www.test.com, and completely wipe them. It could be more than one, of course with different thumbprint, etc.
Unfortunatelly I can not find any PowerShell command removes certificates. I suppose I should query based on dns, then in a loop remove...
Question
Can this task solved at all entirely in Powershell? (remove all certificates with given dns name)
If you have PowerShell v3 or greater this becomes very simple, as PS3 introduced the -DnsName parameter to the Certificate provider options of Get-ChildItem. This will find and delete anything with the DNSName of www.test.com:
Get-ChildItem Cert:\ -Recurse -DnsName 'www.test.com' | Remove-Item
It even supports wildcards, so if you have several certificates that you need to clean up with similar names such as 'mailproxy.test.com', 'www.test.com', and 'ftp.test.com' you could run this:
Get-ChildItem Cert:\ -Recurse -DnsName '*.test.com' | Remove-Item
Simple oneliner for this :
Get-ChildItem -Path Cert:\CurrentUser\My | Where-Object {$_.DnsNameList -contains 'www.domain.org'} | Remove-Item
Remove-Item is the command used to remove a certificate.

Out-File: output file path is not accepted

Still learning and am having a hard time trying to output information to a file: the output file path is not accepted.
My location is PS Cert:\localmachine and here is the entire command:
$cert = Get-ChildItem -Path cert: -Recurse | where { $_.notafter -le (get-date).AddDays(75) -AND $_.notafter -gt (get-date)} | select notafter, issuer, thumbprint, subject | sort-object notafter
$cert | Out-File -FilePath \\ad.dcpds.cpms.osd.mil\WinAdm\Logs\Expiring_Certificates\$hostname.log
The error message I'm getting is:
Out-File : Cannot open file because the current provider (Microsoft.PowerShell.Security\Certificate) cannot open a file.
Based on the comments above, the issue comes from the fact that the current location is somewhere in the certificate provider (cert:).
One possible workaround/solution is to change the current location back to the file provider before writing the file.
$cert = Get-ChildItem -Path cert: -Recurse | where { $_.notafter -le (get-date).AddDays(75) -AND $_.notafter -gt (get-date)} | select notafter, issuer, thumbprint, subject | sort-object notafter
Set-location c:
$cert | out-file -FilePath \\ad.dcpds.cpms.osd.mil\WinAdm\Logs\Expiring_Certificates\$h‌​ostname.log
Second solution: use a path that explicitly includes the filesystem provider:
$cert | out-file -FilePath FileSystem::\\ad.dcpds.cpms.osd.mil\WinAdm\Logs\Expiring_Certificates\$h‌​ostname.log
To complement PoorKenny's effective solutions with background information:
If you use Out-File and the current location is on a drive of a provider OTHER than the filesystem provider:
only drive letter-based paths are recognized as filesystem paths; e.g.:
... | Out-File C:\temp\out.txt # OK, due to using filesystem drive C:
any other path requires prefix FileSystem::, notably including paths such as \path\to\... and even \\server\share\path\to\... (UNC paths); without the prefix, they're interpreted as relative to the current location, whatever its provider, which fails for any provider other than the filesystem provider.
... | Out-File \temp\out.txt # NOT recognized
... | Out-File \\server\share\temp\out.txt # NOT recognized
... | Out-File FileSystem::\temp\out.txt # OK, thanks to 'FileSystem::' prefix
Arguably, given that Out-File only ever creates files, it would make sense to ALWAYS interpret the -FilePath / -LiteralPath arguments as a filesystem path, irrespective of the provider of the current location.
However, the following, from an example that comes with the Out-File help, suggests that the behavior is by design (the (omitted) example invokes Out-File from a current location on the registry provider's drive).
Because Out-File is not supported by the Windows PowerShell Registry provider, you must specify either the file system drive name, such as c:, or the name of the provider followed by two colons, FileSystem::, in the value of the FilePath parameter.
"
If anyone knows whether there truly is a good reason not to always default to the filesystem provider's current location, do let us know.
(Can there be additional, alternative filesystem providers?).