Using Ansible with Proxmox: PART 3A

In this part, we’ll move from preparing our Ansible controller to actually writing our first real automation.

Our goals:

  • Use Ansible to provision a Windows Server 2019 VM

  • Shut it down cleanly

  • And convert it into a Proxmox template — all tag-driven so you can run only the steps you need

  • Use Ansible Vault to keep our Proxmox credentials safe


Step 1: Create Your Playbook File - playbooks/create-windows2019-template.yml

If not done already, lets place our playbook inside the playbooks directory in our Ansible project:

nano ~/Automation/Ansible/playbooks/create-windows2019-template.yml

Paste the following YAML into the file:

# create-windows2019-template.yml
- name: Provision Windows Server 2019 VM and convert to template
  hosts: localhost
  gather_facts: false

  vars_files:
    - ~/Automation/Ansible/group_vars/all/vault.yml   # contains vault_proxmox_api_token_id / secret
    - ~/Automation/Ansible/vars/main.yml              # contains vm_name, storage, etc.

  tasks:    
      - name: Debug API user and token
      debug:
       msg:
        - "User: {{ proxmox_api_user }}"
        - "Token ID: {{ proxmox_api_token_id }}"
        - "Token Secret: {{ proxmox_api_token_secret }}"

    - name: Check if VM already exists
      community.general.proxmox_vm_info:
        api_user: "{{ proxmox_api_user }}"
        api_token_id: "{{ proxmox_api_token_id }}"
        api_token_secret: "{{ proxmox_api_token_secret }}"
        api_host: "{{ proxmox_host }}"
        node: "{{ proxmox_node }}"
      register: vm_info

    - name: Set next available VM ID
      set_fact:
        vm_id: "{{ (vm_info.proxmox_vms | map(attribute='vmid') | max | int) + 1 }}"
      when: vm_info.proxmox_vms | length > 0
      tags: [create]

    - name: Set VM ID to default if no VMs exist
      set_fact:
        vm_id: 9000
      when: vm_info.proxmox_vms | length == 0
      tags: [create]

    - name: Create VM if it does not exist
      community.general.proxmox_kvm:
        api_user: "{{ proxmox_api_user }}"
        api_token_id: "{{ proxmox_api_token_id }}"
        api_token_secret: "{{ proxmox_api_token_secret }}"
        api_host: "{{ proxmox_host }}"
        node: "{{ proxmox_node }}"
        vmid: "{{ vm_id }}"
        name: "{{ vm_name }}"
        cores: 2
        sockets: 1
        memory: 4096
        scsihw: virtio-scsi-pci
        ostype: win10
        boot: cdn
        bootdisk: scsi0
        ide:
          ide2: "{{ iso_storage }},media=cdrom"
        scsi:
          scsi0: "{{ storage }}:32"
        net:
          net0: virtio,bridge=vmbr0
        state: present
      when: vm_name not in (vm_info.proxmox_vms | map(attribute='name') | list)
      tags: [create]

    - name: Stop VM before converting
      community.general.proxmox_kvm:
        api_user: "{{ proxmox_api_user }}"
        api_token_id: "{{ proxmox_api_token_id }}"
        api_token_secret: "{{ proxmox_api_token_secret }}"
        api_host: "{{ proxmox_host }}"
        node: "{{ proxmox_node }}"
        vmid: "{{ vm_id }}"
        state: stopped
      when: >
        vm_info.proxmox_vms |
        selectattr('name', 'equalto', vm_name) |
        map(attribute='status') | first | default('stopped') != 'stopped'
      tags: [stop]

    - name: Convert VM to template
      community.general.proxmox_kvm:
        api_user: "{{ proxmox_api_user }}"
        api_token_id: "{{ proxmox_api_token_id }}"
        api_token_secret: "{{ proxmox_api_token_secret }}"
        api_host: "{{ proxmox_host }}"
        node: "{{ proxmox_node }}"
        vmid: "{{ vm_id }}"
        template: true
      when: >
        vm_info.proxmox_vms |
        selectattr('name', 'equalto', vm_name) |
        map(attribute='template') | first | default(0) | int == 0
      tags: [template]

Save and exit (CTRL+O (ensure filename is correct), Enter, CTRL+X).

Ill make another blogpost that goes through the code and each section of it in detail later on.


Step 2: Create Your Variables File - vars/main.yml

We’ll store key VM details and Proxmox settings in vars/main.yml:

proxmox_host: <proxmox-host-IP-Address>
proxmox_node: pve
vm_id: 9000
vm_name: winserver2019-template
storage: local-lvm
iso_storage: <Path to where ISO is stored>

# Cloud-Init Windows Config
windows_user: Administrator
windows_password: <Password for new Windows Server>
windows_ip: <IP address to assign to Windows Server>
windows_gateway: <Gateway IP Address>
automation/
└── ansible/
    ├── ansible.cfg
    ├── inventories
    │   └── hosts.ini
    ├── requirements.yml
    ├── group_vars/
    │   └── all
    **├── playbooks/
    │   └── create_windows_server2019.yml**

Step 3: Check Your Inventory File - hosts.ini

Edit your hosts.ini to point to your Proxmox server:

[proxmox]
<proxmox-host-IP-Address> ansible_user=ansible ansible_ssh_private_key_file=~/.ssh/id_rsa
  • ansible_user=ansible → tells Ansible which user to log in as.

  • ansible_ssh_private_key_file → uses SSH keys for secure, passwordless login.


Step 4: Ways to run the Playbook

You have two ways of running the playbook:

Method 1:

Run all steps:

ansible-playbook create-windows2019.yml --vault-password-file ~/.vault_pass.txt

Method 2:

Specific step via tags:

ansible-playbook create-windows2019.yml --tags create --vault-password-file ~/.vault_pass.txt

ansible-playbook create-windows2019.yml --tags shutdown --vault-password-file ~/.vault_pass.txt

ansible-playbook create-windows2019.yml --tags template --vault-password-file ~/.vault_pass.txt

We now have a fully working Ansible playbook that can:

  1. Create a new Windows Server 2019 VM in Proxmox,

  2. Shut it down safely,

  3. Convert it into a reusable template — all while keeping your Proxmox credentials encrypted in Ansible Vault.

In Part 3B, we’ll look at running this playbook in another style:

  • Multi-file structured playbooks with Roles for cleaner, reusable automation.

If you feel certain steps or lines of code could have been done more efficiently, please let me know. At the end of the day, positive, constructive criticism, is one of the best ways to grow and improve not only as an IT Professional but life in general.

Thanks!

0
Subscribe to my newsletter

Read articles from Mike Kobbie Tieku TABI directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mike Kobbie Tieku TABI
Mike Kobbie Tieku TABI