0

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:

  1. Duplicate headers are being written to the CSV file.
  2. 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

  1. How can I ensure the CSV header is written only once?
  2. 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

enter image description here

8
  • have you tried running it with $store.Remove($cert) uncommented? what's the output when you allow removing certs? Commented Jul 30 at 7:15
  • @Simon: even if I choose not to execute that, the first part of the check, if there is no certificate present, that also writing multiple headers and rows in csv Commented Jul 30 at 7:19
  • 3
    It is generally a bad practice to make you script error driven by assuming e.g. "An error occurred while accessing the certificate store" could be the only error while virtually all your logic is in the try block. As an aside: try avoid using the increase assignment operator (+=) to create a collection as it is inefficiënt. Commented Jul 30 at 8:06
  • 1
    How are you exceuting the script?, also please note that you dont need to over complicate the creation of the CSV file, $logEntries | Export-Csv -Path $CSVFile -NoTypeInformation -Append alone will create the CSV file if it does not already exist. Commented Jul 30 at 9:22
  • 2
    It seems unlikely that your code would produce the symptom you're describing. Are you looking at the correct output file? Do you also see the problem if you inspect the output file in a plain-text editor? @CraftyB's point was that -Append sensibly 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 single Export-Csv call that uses -Append unconditionally. Commented Jul 30 at 10:59

1 Answer 1

-2

Your code looks fine to me, I can only speculate for reasons.

Could you try it with the -NoHeader option? This is available only after Powershell version 7.4 so pls make sure you have the version requirement.

if (-Not (Test-Path $CSVFile)) {
    $logEntries | Export-Csv -Path $CSVFile -NoTypeInformation
} else {
    # Append with the -NoHeader option
    $logEntries | Export-Csv -Path $CSVFile -NoTypeInformation -Append -NoHeader
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for your response but this solution is not suitable for my environment right now
When -Append is specified, if there's preexisting content in the output file, not adding another header row is implied, so there is no need for -NoHeader. In fact, -NoHeader should arguably be mutually exclusive with -Append, because if there is no preexisting content (either because the output file doesn't exist yet or is empty), combining -Append with -NoHeader creates a header-less file, which cannot (meaningfully) be appended to later with subsequent -Append calls.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.