Tired of Manual Server Setup? Automate SpamExperts in Plesk Like a Pro!

Ever feel like you’re stuck in a loop of repetitive tasks when setting up new servers or extensions? If you’re managing Plesk on Windows servers, you know the drill: install this, configure that, tweak a setting here, and a setting there. It can eat up valuable time and, let’s be honest, it’s not the most exciting work.

But what if I told you there’s a better way? Today, we’re diving into the magic of automation for your Plesk on Windows server setup, specifically for getting the SpamExperts extension up and running in a flash.

Why Bother Automating? Because Your Time is Gold!

SpamExperts is a fantastic tool for keeping nasty emails at bay, but getting it perfectly configured on every server can be a bit of a dance. You’ve got to install it, dig up its unique ID in the database, and then painstakingly input a whole bunch of default settings. Do this manually a few times, and you’ll quickly wish for a magic wand.

That’s where Ansible comes in – our trusty automation sidekick! Ansible lets us define entire server setups in simple, human-readable YAML files. This means less head-scratching, more consistency, and way fewer typos. Think of it as writing down your setup instructions once, and then letting your computer follow them perfectly, every single time.

Let’s Peek Inside Our Automation Playbook

Ready to see how we turn a boring setup into a smooth, automated process? Here’s how our Ansible playbook gets the job done:

Step 1: The Grand Installation!

First things first, we tell Ansible to grab the SpamExperts extension directly from its GitHub release. No manual downloads, no dragging and dropping – just a clean, direct installation.

- name: Install SpamExperts Extension
  win_command: plesk bin extension --install-url https://github.com/SpamExperts/plesk-extension/releases/download/v1.2-7/spamexperts-extension.zip

Step 2: Unearthing the Secret ID

Once installed, every Plesk extension gets a unique “module ID” in the database. Instead of us having to manually find it (which can vary!), our playbook is smart enough to query the Plesk database and fetch it automatically. This makes our playbook super flexible and robust across different server environments.

- name: Get spamexperts-extension module ID
  ansible.windows.win_shell: |
    & 'C:\Program Files (x86)\Plesk\bin\plesk' db "SELECT id FROM modules WHERE name='spamexperts-extension';"

Step 3: Confirmation and Fail-Safe

We then extract that all-important ID. And here’s a crucial part: if for some reason the ID isn’t found (maybe the installation hit a snag?), the playbook will stop and tell us immediately. No silent failures, no guessing games!

Step 4: Setting Everything Just Right (Automatically!)

This is where the real time-saving begins. Our playbook has a complete list of all the essential SpamExperts settings – things like API URLs, crucial MX records, and various operational flags. It then loops through each one:

  • Does the setting already exist? If yes, it skips it.
  • If not? It inserts the setting with its default value, making sure everything is exactly as it should be from the get-go.
- name: "Check and Insert setting: {{ item.setting_name }}"
  loop:
    - { setting_name: 'spampanel_url', value: "{{ spamexperts_initial_api_url }}" }
    # ... and all your other vital settings ...
  ansible.windows.win_shell: |
    # (Behind the scenes, magic happens to check and insert!)

Here is the complete Playbook

---
# playbook_1_initial_spamexperts_setup.yml (CORRECTED YAML SYNTAX)
- name: Initial Setup - Install SpamExperts Extension then Find SpamExperts Module ID and Insert Default Settings
  hosts: windows_servers
  gather_facts: false

  vars:
    spamexperts_initial_api_url: "https://spamfilter-1.example.com"
    spamexperts_initial_api_hostname: "spamfilter-50.example.com"
    spamexperts_initial_api_username: "spamexpertsuser"
    spamexperts_initial_api_password: "123456" # Use Ansible Vault! (Likely encrypted)

    spamexperts_initial_mx1: "mx.example.com"
    spamexperts_initial_mx2: "mx.example.net"
    spamexperts_initial_mx3: "mx.example.nl"
    spamexperts_initial_mx4: "non"

    # CONFIRM THESE EXACT STRING/NUMERIC VALUES
    spamexperts_initial_auto_add_domain: "1"
    spamexperts_initial_auto_del_domain: "1"
    spamexperts_initial_provision_dns: "1"
    spamexperts_initial_set_contact: "0"
    spamexperts_initial_handle_extra_domains: "0"
    spamexperts_initial_handle_only_localdomains: "0"
    spamexperts_initial_redirectback: "0"
    spamexperts_initial_add_domain_loginfail: "0"
    spamexperts_initial_use_ip_address_as_destination_routes: "0"
    spamexperts_initial_support_email: "[email protected]"


  tasks:
    - name: Install SpamExperts Extension 
      win_command: plesk bin extension --install-url https://github.com/SpamExperts/plesk-extension/releases/download/v1.2-7/spamexperts-extension.zip

    - name: Get spamexperts-extension module ID
      ansible.windows.win_shell: |
        & 'C:\Program Files (x86)\Plesk\bin\plesk' db "SELECT id FROM modules WHERE name='spamexperts-extension';"
      register: spamexperts_module_id_query
      changed_when: false

    - name: Extract module ID from query output
      set_fact:
        spamexperts_module_id: "{{ spamexperts_module_id_query.stdout | regex_search('\\|\\s*(\\d+)\\s*\\|', '\\1') | first }}"
      when: spamexperts_module_id_query.stdout is defined and spamexperts_module_id_query.stdout | length > 0

    - name: Fail if module ID not found
      fail:
        msg: "Could not find 'spamexperts-extension' module ID in Plesk database. Ensure the extension is installed."
      when: spamexperts_module_id is not defined or spamexperts_module_id == ''

    # Corrected task to fix YAML indentation and structure
    - name: "Check and Insert setting: {{ item.setting_name }}"
      loop:
        - { setting_name: 'spampanel_url', value: "{{ spamexperts_initial_api_url }}" }
        - { setting_name: 'apihost', value: "{{ spamexperts_initial_api_hostname }}" }
        - { setting_name: 'apiuser', value: "{{ spamexperts_initial_api_username }}" }
        - { setting_name: 'apipass', value: "{{ spamexperts_initial_api_password }}" }
        - { setting_name: 'mx1', value: "{{ spamexperts_initial_mx1 }}" }
        - { setting_name: 'mx2', value: "{{ spamexperts_initial_mx2 }}" }
        - { setting_name: 'mx3', value: "{{ spamexperts_initial_mx3 }}" }
        - { setting_name: 'mx4', value: "{{ spamexperts_initial_mx4 }}" }
        - { setting_name: 'auto_add_domain', value: "{{ spamexperts_initial_auto_add_domain }}" }
        - { setting_name: 'auto_del_domain', value: "{{ spamexperts_initial_auto_del_domain }}" }
        - { setting_name: 'provision_dns', value: "{{ spamexperts_initial_provision_dns }}" }
        - { setting_name: 'set_contact', value: "{{ spamexperts_initial_set_contact }}" }
        - { setting_name: 'handle_extra_domains', value: "{{ spamexperts_initial_handle_extra_domains }}" }
        - { setting_name: 'handle_only_localdomains', value: "{{ spamexperts_initial_handle_only_localdomains }}" }
        - { setting_name: 'redirectback', value: "{{ spamexperts_initial_redirectback }}" }
        - { setting_name: 'add_domain_loginfail', value: "{{ spamexperts_initial_add_domain_loginfail }}" }
        - { setting_name: 'use_ip_address_as_destination_routes', value: "{{ spamexperts_initial_use_ip_address_as_destination_routes }}" }
        - { setting_name: 'support_email', value: "{{ spamexperts_initial_support_email }}" }
      
      ansible.windows.win_shell: |
        $module_id = "{{ spamexperts_module_id }}"
        $setting_name = "{{ item.setting_name }}"
        $setting_value = "{{ item.value }}"
        $changed_status = "UNCHANGED"

        # Check if row exists
        $check_sql = "SELECT COUNT(*) FROM modulesettings WHERE module_id='$module_id' AND name='$setting_name';"
        $check_result = & 'C:\Program Files (x86)\Plesk\bin\plesk' db "$check_sql" 2>&1
        $check_exit_code = $LASTEXITCODE

        if ($check_exit_code -ne 0) {
            Write-Error "Error checking existence of '$setting_name': $($check_result | Out-String)"
            exit 1
        }

        # --- CORRECTED PARSING LOGIC ---
        # Get the line that contains the actual count (should be the 4th line if output is consistent)
        # Using [int] instead of Convert-ToInt32 for potentially cleaner error handling or type conversion.
        # This will fail if the line doesn't contain a number in the expected format.
        $count_line = $check_result[3] # Assuming 0-indexed: 0=header line 1, 1=header line 2, 2=separator, 3=data line
        
        # Extract the number from the data line. This regex specifically looks for a number
        # surrounded by pipes (|), ensuring it's from the data part.
        $match = $count_line | Select-String -Pattern '\|\s*(\d+)\s*\|'
        
        if ($match) {
            $existing_count = [int]$match.Matches[0].Groups[1].Value
        } else {
            Write-Error "Failed to parse count for '$setting_name' from output. Raw output was: $($check_result | Out-String)"
            exit 1 # Fail if parsing fails
        }
        # --- END CORRECTED PARSING LOGIC ---

        if ($existing_count -eq 0) {
            # Insert if not exists
            $insert_sql = "INSERT INTO modulesettings (module_id, name, value) VALUES ('$module_id', '$setting_name', '$setting_value');"
            $insert_result = & 'C:\Program Files (x86)\Plesk\bin\plesk' db "$insert_sql" 2>&1
            $insert_exit_code = $LASTEXITCODE

            if ($insert_exit_code -eq 0) {
                Write-Host "Inserted new setting: $setting_name"
                $changed_status = "CHANGED"
            } else {
                Write-Error "Error inserting setting '$setting_name': $($insert_result | Out-String)"
                exit 1
            }
        } else {
            Write-Host "Setting '$setting_name' already exists, skipping insertion."
        }
        Write-Host $changed_status
      register: db_op_result
      changed_when: "'CHANGED' in db_op_result.stdout"
      no_log: "{{ 'true' if item.setting_name == 'apipass' else 'false' }}"

    - name: Display results of initial settings insertion
      debug:
        msg: "{{ item.stdout }}"
      loop_control:
        label: "{{ item.item.setting_name }}"
      loop: "{{ db_op_result.results }}"

A quick but vital note: You’ll see spamexperts_initial_api_password in the full playbook. For any real-world setup, you’d always want to use Ansible Vault to encrypt sensitive data like passwords. Security first!

Step 5: Seeing the Results

Finally, the playbook gives us a neat summary, showing exactly which settings were added and which ones were already there. Full transparency, no surprises!

By embracing tools like Ansible, we’re not just making our jobs easier; we’re making our infrastructure more reliable, more scalable, and frankly, a lot more fun to manage.


What other tedious server tasks are you hoping to automate? Let me know in the comments!

No votes yet.
Please wait...

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *

Tired of Manual Server Setup? Automate SpamExperts in Plesk Like a Pro!

time to read: 6 min
0