Creating an initial set of Ansible Veeam modules has been my goal for a while. It was clear that this had to be possible with the Ansible concept of Windows modules written in Powershell. A Veeam Backup & Replication server needs to be a Windows Server and the Veeam console is shipped with a feature-rich PowerShell SnapIn, which can be used by the Ansible Windows modules written in Powershell.

So my basic concept is an Ansible PowerShell module running on the Veeam server. As the Veeam Backup & Replication server needs to be a Windows Server, it will be accessed via WinRM by Ansible. I have already written about Ansible and WinRM in my previous blog post: Veeam unattended installation with Ansible
In the current version of the modules, no remote connection to the Veeam Server via PowerShell is planned. So the Veeam Backup & Replication server needs to be accessed via WinRM. If an additional hop via a Windows server with only the Veeam Console installed is required, I would be glad about feedback.
Ansible Veeam Modules
So far I have created just a small set of modules to validate my concept. The goal that I have set myself was to add a VMware ESXi standalone host to the Veeam configuration.
Veeam Facts
This was the first Ansible Veeam Module I have created. It’s a read-only module that gathers configuration details about the Veeam Backup & Replication server. The return can be written into a variable and used by other Ansible Veeam Modules.
#!powershell # Copyright: (c) 2019, Markus Kraus <[email protected]> # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) #Requires -Module Ansible.ModuleUtils.Legacy #AnsibleRequires -OSVersion 6.2 $ErrorActionPreference = "Stop" Set-StrictMode -Version 2.0 # Functions Function Connect-VeeamServer { try { Add-PSSnapin -PassThru VeeamPSSnapIn -ErrorAction Stop | Out-Null } catch { Fail-Json -obj @{} -message "Failed to load Veeam SnapIn on the target: $($_.Exception.Message)" } try { Connect-VBRServer -Server localhost } catch { Fail-Json -obj @{} -message "Failed to connect VBR Server on the target: $($_.Exception.Message)" } } Function Disconnect-VeeamServer { try { Disconnect-VBRServer } catch { Fail-Json -obj @{} -message "Failed to disconnect VBR Server on the target: $($_.Exception.Message)" } } # Connect Connect-VeeamServer # Create a new result object $result = @{ changed = $false veeam_facts = @{ veeam_connection = @() veeam_repositories = @() veeam_servers = @() veeam_credentials = @() } } # Get Veeam Connection try { $Connection = Get-VBRServerSession } catch { Fail-Json -obj $result -message "Failed to get connection details on the target: $($_.Exception.Message)" } # Get Veeam Server try { [Array]$ServerList = Get-VBRServer } catch { Fail-Json -obj $result -message "Failed to get server details on the target: $($_.Exception.Message)" } # Get Veeam Repositories try { [Array]$RepoList = Get-VBRBackupRepository | Where-Object {$_.Type -ne "SanSnapshotOnly"} } catch { Fail-Json -obj $result -message "Failed to get repository details on the target: $($_.Exception.Message)" } # Get Veeam Credentials try { [Array]$CredList = Get-VBRCredentials } catch { Fail-Json -obj $result -message "Failed to get credential details on the target: $($_.Exception.Message)" } # Create result $connection_info = @{} $connection_info["user"] = $Connection.user $connection_info["server"] = $Connection.server $connection_info["port"] = $Connection.port $result.veeam_facts.veeam_connection += $connection_info foreach ($Repo in $RepoList) { $repo_info = @{} $repo_info["name"] = $repo.name $repo_info["type"] = $repo.typedisplay $repo_info["host"] = $($ServerList | Where-Object {$_.Id -eq $repo.HostId}).name $repo_info["friendlypath"] = $repo.friendlypath $repo_info["description"] = $repo.description $result.veeam_facts.veeam_repositories += $repo_info } foreach ($Server in $ServerList) { $server_info = @{} $server_info["id"] = $server.id $server_info["name"] = $server.name $server_info["description"] = $server.description $server_info["type"] = $server.info.typedescription $result.veeam_facts.veeam_servers += $server_info } foreach ($Cred in $CredList) { $cred_info = @{} $cred_info["id"] = $cred.id $cred_info["name"] = $cred.name $cred_info["username"] = $cred.username $cred_info["encryptedpassword"] = $cred.encryptedpassword $cred_info["description"] = $cred.description $result.veeam_facts.veeam_credentials += $cred_info } # Disconnect Disconnect-VeeamServer # Return result Exit-Json -obj $result
ok: [10.0.2.16] => { "my_facts": { "changed": false, "failed": false, "veeam_facts": { "veeam_connection": [ { "port": 9392, "server": "localhost", "user": "VEEAM01\\Administrator" } ], "veeam_credentials": [ { "description": "Lab User for Standalone Host", "encryptedpassword": null, "id": "ae0fa0f8-d0ed-4014-9e0c-b84d56bc9084", "name": "root", "username": "root" } ], "veeam_repositories": [ { "description": "Created by Veeam Backup", "friendlypath": "C:\\Backup", "host": "Veeam01", "name": "Default Backup Repository", "type": "Windows" } ], "veeam_servers": [ { "description": "Backup server", "id": "6745a759-2205-4cd2-b172-8ec8f7e60ef8", "name": "Veeam01", "type": "Microsoft Windows Server" }, { "description": "Created by Powershell at 25.06.2019 22:39:24.", "id": "aedd0693-657c-4384-9e53-cd6bb605a637", "name": "192.168.234.101", "type": "VMware ESXi Server" } ] } } }
A simple Ansible playbook that returns all veeam server facts looks like that:
- name: Get all VBR Facts hosts: veeam gather_facts: no tasks: - name: Get Veeam Facts veeam_connection_facts: register: my_facts - name: Debug Veeam Facts debug: var: my_facts
Veeam Credentials
The next step towards manage servers in Veeam Backup & Replication is adding the required credentials. The veeam_credential module is able to add and remove credentials of the types Windows, Linux and Standard. The return of the add method (state: present) is the ID of the newly created credentials. This ID can be used by other Ansible Veeam Modules.
In addition to the PowerShell script, all Ansible Windows Modules do have a python “script” that contains the documentation of

#!powershell # Copyright: (c) 2019, Markus Kraus <[email protected]> # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) #Requires -Module Ansible.ModuleUtils.Legacy #AnsibleRequires -OSVersion 6.2 #AnsibleRequires -CSharpUtil Ansible.Basic $spec = @{ options = @{ type = @{ type = "str"; choices = "windows", "linux", "standard"; default = "standard" } username = @{ type = "str" } password = @{ type = "str" } state = @{ type = "str"; choices = "absent", "present"; default = "present" } description = @{ type = "str"; default = "Created by Ansible"} id = @{ type = "str"} } required_if = @(@("state", "present", @("username", "password")), @("state", "absent", @("id"))) supports_check_mode = $true } $module = [Ansible.Basic.AnsibleModule]::Create($args, $spec) $ErrorActionPreference = "Stop" Set-StrictMode -Version 2.0 # Functions Function Connect-VeeamServer { try { Add-PSSnapin -PassThru VeeamPSSnapIn -ErrorAction Stop | Out-Null } catch { Fail-Json -obj @{} -message "Failed to load Veeam SnapIn on the target: $($_.Exception.Message)" } try { Connect-VBRServer -Server localhost } catch { Fail-Json -obj @{} -message "Failed to connect VBR Server on the target: $($_.Exception.Message)" } } Function Disconnect-VeeamServer { try { Disconnect-VBRServer } catch { Fail-Json -obj @{} -message "Failed to disconnect VBR Server on the target: $($_.Exception.Message)" } } # Connect Connect-VeeamServer switch ( $module.Params.state) { "present" { if ($module.Params.type -eq "standard") { $Cred = Add-VBRCredentials -User $module.Params.username -Password "$($module.Params.password)" -Description "$($module.Params.description)" } else { $Cred = Add-VBRCredentials -Type $module.Params.type -User $module.Params.username -Password "$($module.Params.password)" -Description "$($module.Params.description)" } $module.Result.changed = $true $module.Result.id = $Cred.id } "absent" { $RemoveCred = Get-VBRCredentials | Where-Object {$_.id -eq $module.Params.id} $Cred = Remove-VBRCredentials -Credential $RemoveCred $module.Result.changed = $true } Default {} } # Disconnect Disconnect-VeeamServer # Return result $module.ExitJson()
ok: [10.0.2.16] => { "my_cred": { "changed": true, "failed": false, "id": "86a42430-5756-4921-9d06-fd1d56599741" } }
A simple playbook that creates new Veeam Server Credentials looks like that:

- name: Add new Credentials to VBR Server hosts: veeam gather_facts: no vars: query: "veeam_facts.veeam_credentials[?id=='{{ my_cred.id }}']" my_password: !vault | $ANSIBLE_VAULT;1.1;AES256 tasks: - name: Add Credential veeam_credential: state: present type: windows username: Administrator password: "{{ my_password }}" description: My dummy description register: my_cred - name: Debug Veeam Credentials debug: var: my_cred - name: Get Veeam Facts veeam_connection_facts: register: my_facts - name: Debug Veeam Credential Facts debug: var: my_facts | json_query(query) - name: Remove Credential veeam_credential: state: absent id: "{{ my_cred.id }}"
Veeam Servers
The next part of my preview is an Ansible module that is able to add servers to the Veeam Backup & Replication configuration. A server in Veeam jargon can be for example a VMware ESXi, a VMware vCenter or a Windows server (more server types). The initial version of the Ansible module can only add VMware ESXi Servers.
#!powershell # Copyright: (c) 2019, Markus Kraus <[email protected]> # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) #Requires -Module Ansible.ModuleUtils.Legacy #AnsibleRequires -OSVersion 6.2 #AnsibleRequires -CSharpUtil Ansible.Basic $spec = @{ options = @{ type = @{ type = "str"; choices = "esxi", "vcenter", "windows"; default = "esxi" } credential_id = @{ type = "str" } state = @{ type = "str"; choices = "absent", "present"; default = "present" } name = @{ type = "str" } id = @{ type = "str" } } required_if = @(@("state", "present", @("type", "name", "credential_id")), @("state", "absent", @("id"))) supports_check_mode = $true } $module = [Ansible.Basic.AnsibleModule]::Create($args, $spec) $ErrorActionPreference = "Stop" Set-StrictMode -Version 2.0 # Functions Function Connect-VeeamServer { try { Add-PSSnapin -PassThru VeeamPSSnapIn -ErrorAction Stop | Out-Null } catch { Fail-Json -obj @{} -message "Failed to load Veeam SnapIn on the target: $($_.Exception.Message)" } try { Connect-VBRServer -Server localhost } catch { Fail-Json -obj @{} -message "Failed to connect VBR Server on the target: $($_.Exception.Message)" } } Function Disconnect-VeeamServer { try { Disconnect-VBRServer } catch { Fail-Json -obj @{} -message "Failed to disconnect VBR Server on the target: $($_.Exception.Message)" } } # Connect Connect-VeeamServer switch ( $module.Params.state) { "present" { $Cred = Get-VBRCredentials | Where-Object {$_.id -eq $module.Params.credential_id} switch ($module.Params.type) { "esxi" { $Server = Add-VBRESXi –Name $module.Params.name -Credentials $Cred $module.Result.changed = $true $module.Result.id = $Server.id } "vcenter" {Fail-Json -obj @{} -message "Type not yet implemented." } "windows" {Fail-Json -obj @{} -message "Type not yet implemented." } Default { } } } "absent" { Fail-Json -obj @{} -message "State not yet implemented." } Default {} } # Disconnect Disconnect-VeeamServer # Return result $module.ExitJson()
ok: [10.0.2.16] => { "my_facts.veeam_facts.veeam_servers": [ { "description": "Backup server", "id": "6745a759-2205-4cd2-b172-8ec8f7e60ef8", "name": "Veeam01", "type": "Microsoft Windows Server" }, { "description": "Created by Powershell at 25.06.2019 22:39:24.", "id": "aedd0693-657c-4384-9e53-cd6bb605a637", "name": "192.168.234.101", "type": "VMware ESXi Server" } ] }
A simple playbook that executes all required tasks to add a new VMware ESXi Server to the Veeam Backup & Replication configuration looks like that:

- name: Add ESXi Host to VBR Server hosts: veeam gather_facts: no vars: root_password: !vault | $ANSIBLE_VAULT;1.1;AES256 tasks: - name: Add root credential veeam_credential: state: present type: standard username: root password: "{{ root_password }}" description: "Lab User for Standalone Host" register: root_cred - name: Debug root credential debug: var: root_cred - name: Add esxi server veeam_server: state: present type: esxi credential_id: "{{ root_cred.id }}" name: 192.168.234.101 register: esxi_server - name: Get Veeam Facts veeam_connection_facts: register: my_facts - name: Debug Veeam Servers from Facts debug: var: my_facts.veeam_facts.veeam_servers
GitHub Project
The Ansible Veeam Modules and example playbooks are available via GitHub. The source code state at the publishing date of this blog post is a dedicated release number:
Feel free to contribute to the project by opening an issue, creating a pull request, leaving a comment or using the feedback form for the Veeam Ansible Module. Every input is welcome!
Thanks for the article. Many a times, YAML playbooks during execution giving syntax errors and unable to get the auto spacing in any of editors. Need your suggestions, how to write and execute a clear syntax error free YAML playbooks, Thanks
Hi VJ,
I feel your pain.
But with the VSCode ansible extension I do feel very comfortable.
Best regards
Markus
I will look into contributing as we use Ansible and Veeam but can you please fix the repo name before adding much more? Thanks.
Oh… You are right the Repo name should be fixed. I will do that as soon as possible.
But I will also restructure this Repo (see branch “CreateRole”) and do further development in the dedicated veeam role:
https://github.com/mycloudrevolution/veeam
This role will then be linked as submodule to the existing Ansible-Veeam Repo.
First version of the Veeam role is already published:
https://galaxy.ansible.com/mycloudrevolution/veeam