Created
February 10, 2026 08:23
-
-
Save dwilliamsuk/3da97cd05dac680fa47edfb02bf2aec7 to your computer and use it in GitHub Desktop.
PowerShell script to add the certificate of a ClickOnce app publisher to the "Trusted Publisher" certificate store for the current user. This allows ClickOnce apps to launch without prompting the user for trust. Requires the ClickOnce app to be signed with a certificate.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| This script trusts a ClickOnce app publisher for a user. | |
| .DESCRIPTION | |
| This script adds the certificate of a ClickOnce app publisher to the "Trusted Publisher" | |
| certificate store for the current user. This allows ClickOnce apps to launch without | |
| prompting the user for trust. | |
| .PARAMETER ApplicationManifestURL | |
| This is the URL of the ClickOnce application manifest file you want to trust. | |
| - Type: [Uri] | |
| - Mandatory: True | |
| .EXAMPLE | |
| An example of running this script is shown below. | |
| PS C:\> .\Trust-ClickOnce.ps1 -ApplicationManifestURL "https://example.com/ExampleApp.application" | |
| .NOTES | |
| Author: github.com/dwilliamsuk | |
| Date: 14/10/2025 | |
| Version: 1.0 | |
| Script Purpose: Trusts a ClickOnce app publisher for a user. | |
| Dependencies: N/A | |
| #> | |
| function Get-ClickOnce-Publisher-x509 { | |
| param ( | |
| [Uri]$ManifestURL | |
| ) | |
| $web_request_object = Invoke-WebRequest -UseBasicParsing -Method "GET" -Uri $ManifestURL | |
| if ( ($web_request_object) -and ($web_request_object.StatusCode -eq 200) ) { | |
| # Store response in variable as XML object | |
| $application_manifest = [xml]::new() | |
| $application_manifest.Load($web_request_object.RawContentStream) | |
| # Get x509 signing certs in manifest | |
| $application_manifest_x509_subject = $application_manifest.assembly.Signature.KeyInfo.RelData.license.grant.AuthenticodePublisher.X509SubjectName | |
| $application_manifest_x509_data = $application_manifest.assembly.Signature.KeyInfo.RelData.license.issuer.Signature.KeyInfo.X509Data | |
| # For each x509 cert, find the cert of the publisher and add to trusted publisher store. | |
| # This loop doesn't add the rest of the CA chain, as Windows will grab CA certs at | |
| # runtime via Windows Update. | |
| foreach ($x509_certificate in $application_manifest_x509_data.X509Certificate) { | |
| $decoded_x509_certificate = [Convert]::FromBase64String($x509_certificate) | |
| $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($decoded_x509_certificate) | |
| # Match for app cert (the only one we want to trust) | |
| if ($certificate.Subject -eq $application_manifest_x509_subject) { | |
| return $certificate | |
| } else { | |
| $certificate.Dispose() | |
| } | |
| } | |
| throw "Unable to find publisher x509 cert!" | |
| } else {throw "Web request failed!"} | |
| } | |
| function Trust-Publisher-X509 { | |
| param ( | |
| [System.Security.Cryptography.X509Certificates.X509Certificate2]$X509Cert | |
| ) | |
| $CertStore = New-Object System.Security.Cryptography.X509Certificates.X509Store -ArgumentList "TrustedPublisher", "CurrentUser" | |
| $CertStore.Open('ReadWrite') | |
| $CertStore.Add($X509Cert) | |
| $CertStore.Close() | |
| return | |
| } | |
| $ApplicationManifestURL = $args[0] | |
| $PublisherCert = Get-ClickOnce-Publisher-x509 -ManifestURL $ApplicationManifestURL | |
| Write-Output "Found certificate! $($PublisherCert.DnsNameList.Unicode) [$($PublisherCert.Thumbprint)]" | |
| Trust-Publisher-X509 -X509Cert $PublisherCert | |
| Write-Output "Trusted certificate!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment