I'm using the following PowerShell script to remove self-signed certificates from a server. Based on the outcome, I log the results to a CSV file. However, I'm encountering two issues:
- Duplicate headers are being written to the CSV file.
- Duplicate rows are appearing in the output.
$server = $env:COMPUTERNAME
$CSVFile = "C:\CertRemoval.csv"
$logEntries = @()
try {
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My", "LocalMachine")
$store.Open("ReadWrite")
$certsToRemove = $store.Certificates | Where-Object {
$_.Subject -like "CN=$server*" -and
$_.Issuer -like "CN=$server*"
}
if ($certsToRemove.Count -eq 0) {
$logEntries += [PSCustomObject]@{
Timestamp = Get-Date
Status = "Info"
Subject = ""
Issuer = ""
Message = "No certificates found for removal"
}
} else {
foreach ($cert in $certsToRemove) {
Write-Host "Removing certificate: $($cert.Subject)"
try {
# Uncomment to actually remove the certificate
# $store.Remove($cert)
$logEntries += [PSCustomObject]@{
Timestamp = Get-Date
Status = "Success"
Subject = $cert.Subject
Issuer = $cert.Issuer
Message = "Certificate removed successfully"
}
} catch {
$logEntries += [PSCustomObject]@{
Timestamp = Get-Date
Status = "Error"
Subject = $cert.Subject
Issuer = $cert.Issuer
Message = "Failed to remove certificate: $_"
}
}
}
}
$store.Close()
}
catch {
$logEntries += [PSCustomObject]@{
Timestamp = Get-Date
Status = "Fatal Error"
Subject = ""
Issuer = ""
Message = "An error occurred while accessing the certificate store: $_"
}
}
# Export log to CSV with header only if file doesn't exist
if (-Not (Test-Path $CSVFile)) {
$logEntries | Export-Csv -Path $CSVFile -NoTypeInformation
} else {
$logEntries | Export-Csv -Path $CSVFile -NoTypeInformation -Append
}
Issue
Even though I’m using -Append when the file exists, the script still writes the header row again and sometimes duplicates log entries.
What I Need Help With
- How can I ensure the CSV header is written only once?
- How can I prevent duplicate rows from being written when the script runs multiple times?
Any insights or improvements would be appreciated!
Output for reference

$store.Remove($cert)uncommented? what's the output when you allow removing certs?tryblock. As an aside: try avoid using the increase assignment operator (+=) to create a collection as it is inefficiënt.$logEntries | Export-Csv -Path $CSVFile -NoTypeInformation -Appendalone will create the CSV file if it does not already exist.-Appendsensibly creates the headers if the output file doesn't exist yet or is empty, and omits them when appending to preexisting content. Thus, you can make do with a singleExport-Csvcall that uses-Appendunconditionally.