ansible.windows
ansible.windows copied to clipboard
Can't use string containing \" in multi-line win_shell
SUMMARY
When using a multi-line win_shell
command, such as:
- name: Enable basic auth
ansible.windows.win_shell: |
Import-Module WebAdministration
$IISPath = "IIS:\"
...
ansible-playbook
fails with:
ERROR! failed at splitting arguments, either an unbalanced jinja2 block or quotes:
ISSUE TYPE
- Bug Report
COMPONENT NAME
Module ansible.windows.win_shell
.
ANSIBLE VERSION
ansible 2.10.1
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/dave/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/dave/.local/lib/python3.6/site-packages/ansible
executable location = /home/dave/.local/bin/ansible
python version = 3.6.9 (default, Oct 8 2020, 12:12:24) [GCC 8.4.0]
CONFIGURATION
DEFAULT_VAULT_PASSWORD_FILE(env: ANSIBLE_VAULT_PASSWORD_FILE) = /home/dave/code/ops/.vault_pass.txt
OS / ENVIRONMENT
Target is Windows Server 2019 Standard (1809). Connecting with WinRM.
$PSVersionTable.PSVersion
Major Minor Build Revision
----- ----- ----- --------
5 1 17763 1432
STEPS TO REPRODUCE
- name: Enable basic auth
ansible.windows.win_shell: |
$ErrorActionPreference = "Stop"
Import-Module WebAdministration
$IISPath = "IIS:\"
$FTPUserGroupName = "FTP Users"
$FTPSiteName = 'FTP Site'
$FTPSitePath = "IIS:\Sites\$FTPSiteName"
$BasicAuth = 'ftpServer.security.authentication.basicAuthentication.enabled'
Set-ItemProperty -Path $FTPSitePath -Name $BasicAuth -Value $True
$Param = @{
Filter = "/system.ftpServer/security/authorization"
Value = @{
accessType = "Allow"
roles = "$FTPUserGroupName"
permissions = 1
}
Location = $FTPSiteName
PSPath = $IISPath
}
Add-WebConfiguration @param
echo $null >> C:\ftp\.ansible_state\basic_auth
args:
creates: C:\ftp\.ansible_state\basic_auth
EXPECTED RESULTS
Task completes.
ACTUAL RESULTS
$ ansible-playbook -i hosts.yml -l ftp_servers deploy.yml
ERROR! failed at splitting arguments, either an unbalanced jinja2 block or quotes: $ErrorActionPreference = "Stop"
Import-Module WebAdministration
$IISPath = "IIS:\"
$FTPUserGroupName = "FTP Users"
$FTPSiteName = 'FTP Site'
$FTPSitePath = "IIS:\Sites\$FTPSiteName"
$BasicAuth = 'ftpServer.security.authentication.basicAuthentication.enabled'
Set-ItemProperty -Path $FTPSitePath -Name $BasicAuth -Value $True
$Param = @{
Filter = "/system.ftpServer/security/authorization"
Value = @{
accessType = "Allow"
roles = "$FTPUserGroupName"
permissions = 1
}
Location = $FTPSiteName
PSPath = $IISPath
}
Add-WebConfiguration @param
echo $null >> C:\ftp\.ansible_state\basic_auth
The error appears to be in '/home/dave/code/ops/deploy.yml': line 116, column 7, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: Enable basic auth
^ here
I tried to workaround with various combinations of escaping, but always got the same error if there was a \
followed by "
anywhere. Changing "
to '
did not help.
As a workaround I did this:
$IISPath = "IIS:\ Padding for Jinja2/Ansible bug".substring(0, 5)
🤢
There's definitely some weirdness in using multi-line strings in the parser (I don't think this is related to win_shell
, it would happen with anything, even just a var definition). For example, you can't have comments (starting with #
) in the multi-line string either. I wasted an hour on that the other day.
If you're not doing any jinja templating in the string (using {{ }}
) (or actually, maybe even if you are it doesn't matter because https://github.com/ansible/ansible/issues/4638) you can mark it as raw for jinja purposes, which is how I worked around the weirdness.
- name: Enable basic auth
ansible.windows.win_shell: |
{% raw %}
$ErrorActionPreference = "Stop"
Import-Module WebAdministration
$IISPath = "IIS:\"
$FTPUserGroupName = "FTP Users"
$FTPSiteName = 'FTP Site'
$FTPSitePath = "IIS:\Sites\$FTPSiteName"
$BasicAuth = 'ftpServer.security.authentication.basicAuthentication.enabled'
Set-ItemProperty -Path $FTPSitePath -Name $BasicAuth -Value $True
$Param = @{
Filter = "/system.ftpServer/security/authorization"
Value = @{
accessType = "Allow"
roles = "$FTPUserGroupName"
permissions = 1
}
Location = $FTPSiteName
PSPath = $IISPath
}
Add-WebConfiguration @param
echo $null >> C:\ftp\.ansible_state\basic_auth
{% endraw %}
args:
creates: C:\ftp\.ansible_state\basic_auth
That may be a better workaround for your use case; I'm certainly going to keep it in mind whenever I'm pasting existing scripts into win_shell
. Give it a try!
Yea this is definitely not an issue with win_shell
but rather how Ansible parses a raw string in a module. It is trying to handle the older style of module args like - win_shell: Test-Function chdir=C:\Windows
. Unfortunately there are some false positives when it comes to interpreting quotes, especially ones after \
. There's probably some more things we can do to make it better but this should be reported in ansible/ansible as that is where the parsing is happening.
I thought this was already a reported issue but I can't seem to find it right now so will keep this open until I do or have opened a new issue for it.
Just a heads up: Using {% raw %}
/ {% endraw %}
as given above doesn't resolve the issue for me 😞
The only workaround I know when you have a string that contains \"
is to template the backslash like so
- set_fact:
backslash: \
- win_shell: |
Get-Item -Path "C:\Windows{{ backslash }}"
Not ideal but it works because Ansible parses the value first to scan for module args before templating the values.