Important note about SSL VPN compatibility for 20.0 MR1 with EoL SFOS versions and UTM9 OS. Learn more in the release notes.

This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Upload certificates using Powershell to automate Let's encrypt

After reading quite a lot about the lack of support for Let's encrypt and studying the various solutions other people came up with I wanted to post my solution.

Over the last couple of days I wrote a script to upload a certificate to the firewall, update any WAF rules and optionally replace the admin portal certificate.

The sole purpose of this script is to upload a certificate, so it does not interact with Let's encrypt at all. This makes it very flexible, as it can be integrated in any workflow.
At the moment it can look in the local certificate store or read .pfx certificate files, but I invite anybody to add support for .pem, or do other improvements.

The only requirements are Powershell 7 and a XG user account with API access.

The script can be found on GitHub.

Here's an example use case:

Upload-Cert.ps1 "https://fw:4444//webconsole/APIController" $Credential -CertificateFriendlyName "R3" -UpdateAdminCertificate

This thread was automatically locked due to age.
  • Added this file to the HowTo Section in recommended Reads. 

     Sophos Firewall: [LetsEncrypt] How To in Sophos Firewall 



  • Hi Martin,

    Thank you for sharing this with the Community. 

    Erick Jan
    Community Support Engineer | Sophos Technical Support
    Sophos Support Videos Product Documentation  |  @SophosSupport  | Sign up for SMS Alerts
    If a post solves your question use the 'Verify Answer' link.

  • Hi  ,

    thank you very much for sharing that script.

    I am trying to get that working and I am very far, but I have a little problem that I can't come over: The script is updating every WAF rule, not just the WAF rule group that is mentioned at the -RulesGroup option.

    I am starting your script with my own script, to let it run as a scheduled task:

    $FwRulesGroup = "WAF-3CX-https"
    $FwURL = ""
    $Certname = "" 
    $CertPath = "C:\SYSTEM\Scripte\$($Certname).pfx"
    $username = "MyUser"
    $password = ConvertTo-SecureString "MyPassword" -AsPlainText -Force
    $Credentials = New-Object System.Management.Automation.PSCredential($username, $password)
    $Thumbprint = (New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertPath, $password)).Thumbprint
    write-host "Running Cert-to-XGS"
    & "$($PSScriptRoot)\Cert-to-XGS.ps1" $FwURL $Credentials -CertificateFriendlyName $Certname -FriendlyName $Thumbprint -RulesGroup $FwRulesGroup -DeleteOldCertificates -verbose

    I am very experienced with Powershell (but unfortunately not with the Sophos API).

    I only made 3 changes to your script:

    1. At row 351 there is a $ missing at $false

    2. At row 463 there is a space missing after the word containing

    3. I have commented out lines 494 and 495 because I only need the thumbprint as the cert name to check whether it is a new certificate or not, so that your script enters the section "Certificate with that name already exists", even at the next month.

    Your script is running perfect until the point where the successful uploaded cert should be updated at the WAF rule. All WAF rules are getting updated with that cert even that the WAF-Group name does not match and also the domains does not match.

    Is there a way to get in touch with you to troubleshoot the script?

    Best regards from Landshut,


  • Hi Johnny,

    I did not have that problem, so I can't help too much.

    One thing to check is line 302, where the script checks if the rule contains any domain from the certificate using the function 'ContainsAll'.
    The script actually only checks the used domain, not the group of the rule.


  • Thank you very much for your hint, I was able to track it down.

    At first to the -Rulesgroup switch. I thought that this is made to update the certs from all WAF rules that are member of that group but know I've seen, that the switch moves the rules to the group with that name after updating.

    I got the script now working for me after I changed the line 182 from

    if (-not $List -match $Element) {


    if ($List -notcontains $Element) {

    Now 5 webservers are left alone and 4 webservers are updated, just as it should be.

    But one thing: The script updates WAF groups regardless if they are Port 80 only with disabled https or not. That means the script updates the cert section but https remains disabled, so I don't worry about that. But it would be elegant to skip rules where the https checkbox is not set.

    As next I will test how it works with wildcard certs and provide some code if it does not work out of the box.

    Once again: Thank you very much for sharing! If you have a donation link/address I would be happy to send you 30 coffees :-)

  • You are right, that is how that line should be.
    I updated the code with your changes.

    I'll see what I can do with regards to the https. It sounds like a good feature, If I find the time I'll try to implement it.

    I don't think wildcard works right now, as the code checks for the explicit domain names in the certificate. This would have to be expanded to match wildcards.

    I'm glad you found the script useful. I'm just happy to help.

  • Hi Martin,

    I just tried the script at another webserver (Exchange) and there is my updated code not working, because the cert has 2 URLs, and

    With the first name in the cert it is working, but with autodiscover (alternate DNS at the cert) not.

    But now I changed Line 182 to

    if (!($List -Match $Element)) {

    And now it works very well with both webservers mentioned at the cert.