From fc7980af9a42676913b4054163570ee438b82e9c Mon Sep 17 00:00:00 2001 From: Brian Scholer <1260690+briantist@users.noreply.github.com> Date: Tue, 4 Feb 2020 01:34:11 -0500 Subject: [PATCH] Fix UNC path support in the powershell shell plugin (#66604) * Fix UNC path joining in the powershell shell plugin, add test * Remove testy bits and a redundant line * Fix style nits * Update to use os.ntpath * Add changelog for #66604 --- .../fragments/66604-powershell-unc-paths.yml | 2 ++ lib/ansible/plugins/shell/powershell.py | 16 ++++++++-------- test/units/plugins/shell/test_powershell.py | 10 +++++++++- 3 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 changelogs/fragments/66604-powershell-unc-paths.yml diff --git a/changelogs/fragments/66604-powershell-unc-paths.yml b/changelogs/fragments/66604-powershell-unc-paths.yml new file mode 100644 index 00000000000..a79bcc857ad --- /dev/null +++ b/changelogs/fragments/66604-powershell-unc-paths.yml @@ -0,0 +1,2 @@ +minor_changes: + - "powershell (shell plugin) - Fix `join_path` to support UNC paths (https://github.com/ansible/ansible/issues/66341)" diff --git a/lib/ansible/plugins/shell/powershell.py b/lib/ansible/plugins/shell/powershell.py index ee23147cc5d..ca2d5ebf5ba 100644 --- a/lib/ansible/plugins/shell/powershell.py +++ b/lib/ansible/plugins/shell/powershell.py @@ -22,6 +22,7 @@ import re import shlex import pkgutil import xml.etree.ElementTree as ET +import ntpath from ansible.errors import AnsibleError from ansible.module_utils._text import to_bytes, to_text @@ -93,14 +94,13 @@ class ShellModule(ShellBase): return "" def join_path(self, *args): - parts = [] - for arg in args: - arg = self._unquote(arg).replace('/', '\\') - parts.extend([a for a in arg.split('\\') if a]) - path = '\\'.join(parts) - if path.startswith('~'): - return path - return path + # use normpath() to remove doubled slashed and convert forward to backslashes + parts = [ntpath.normpath(self._unquote(arg)) for arg in args] + + # Becuase ntpath.join treats any component that begins with a backslash as an absolute path, + # we have to strip slashes from at least the beginning, otherwise join will ignore all previous + # path components except for the drive. + return ntpath.join(parts[0], *[part.strip('\\') for part in parts[1:]]) def get_remote_filename(self, pathname): # powershell requires that script files end with .ps1 diff --git a/test/units/plugins/shell/test_powershell.py b/test/units/plugins/shell/test_powershell.py index a73070c6895..6da7ffd5e66 100644 --- a/test/units/plugins/shell/test_powershell.py +++ b/test/units/plugins/shell/test_powershell.py @@ -1,4 +1,4 @@ -from ansible.plugins.shell.powershell import _parse_clixml +from ansible.plugins.shell.powershell import _parse_clixml, ShellModule def test_parse_clixml_empty(): @@ -51,3 +51,11 @@ def test_parse_clixml_multiple_streams(): expected = b"hi info" actual = _parse_clixml(multiple_stream, stream="Info") assert actual == expected + + +def test_join_path_unc(): + pwsh = ShellModule() + unc_path_parts = ['\\\\host\\share\\dir1\\\\dir2\\', '\\dir3/dir4', 'dir5', 'dir6\\'] + expected = '\\\\host\\share\\dir1\\dir2\\dir3\\dir4\\dir5\\dir6' + actual = pwsh.join_path(*unc_path_parts) + assert actual == expected