# Buggy code
def _build_winrm_kwargs(self):
    # this used to be in set_options, as win_reboot needs to be able to
    # override the conn timeout, we need to be able to build the args
    # after setting individual options. This is called by _connect before
    # starting the WinRM connection
    self._winrm_host = self.get_option("remote_addr")
    self._winrm_user = self.get_option("remote_user")
    self._winrm_pass = self._play_context.password

    self._become_method = self._play_context.become_method
    self._become_user = self._play_context.become_user
    self._become_pass = self._play_context.become_pass

    self._winrm_port = self.get_option("port")

    self._winrm_scheme = self.get_option("scheme")
    # old behaviour, scheme should default to http if not set and the port
    # is 5985 otherwise https
    if self._winrm_scheme is None:
        self._winrm_scheme = "http" if self._winrm_port == 5985 else "https"

    self._winrm_path = self.get_option("path")
    self._kinit_cmd = self.get_option("kerberos_command")
    self._winrm_transport = self.get_option("transport")
    self._winrm_connection_timeout = self.get_option("connection_timeout")

    if hasattr(winrm, "FEATURE_SUPPORTED_AUTHTYPES"):
        self._winrm_supported_authtypes = set(winrm.FEATURE_SUPPORTED_AUTHTYPES)
    else:
        # for legacy versions of pywinrm, use the values we know are supported
        self._winrm_supported_authtypes = set(["plaintext", "ssl", "kerberos"])

    # calculate transport if needed
    if self._winrm_transport is None or self._winrm_transport[0] is None:
        # TODO: figure out what we want to do with auto-transport selection in the face of NTLM/Kerb/CredSSP/Cert/Basic
        transport_selector = ["ssl"] if self._winrm_scheme == "https" else ["plaintext"]

        if HAVE_KERBEROS and (self._winrm_user and "@" in self._winrm_user):
            self._winrm_transport = ["kerberos"] + transport_selector
        else:
            self._winrm_transport = transport_selector

    unsupported_transports = set(self._winrm_transport).difference(
        self._winrm_supported_authtypes
    )

    if unsupported_transports:
        raise AnsibleError(
            "The installed version of WinRM does not support transport(s) %s"
            % to_native(list(unsupported_transports), nonstring="simplerepr")
        )

    # if kerberos is among our transports and there's a password specified, we're managing the tickets
    kinit_mode = self.get_option("kerberos_mode")
    if kinit_mode is None:
        # HACK: ideally, remove multi-transport stuff
        self._kerb_managed = "kerberos" in self._winrm_transport and (
            self._winrm_pass is not None and self._winrm_pass != ""
        )
    elif kinit_mode == "managed":
        self._kerb_managed = True
    elif kinit_mode == "manual":
        self._kerb_managed = False

    # arg names we're going passing directly
    internal_kwarg_mask = set(
        [
            "self",
            "endpoint",
            "transport",
            "username",
            "password",
            "scheme",
            "path",
            "kinit_mode",
            "kinit_cmd",
        ]
    )

    self._winrm_kwargs = dict(username=self._winrm_user, password=self._winrm_pass)
    argspec = inspect.getargspec(Protocol.__init__)
    supported_winrm_args = set(argspec.args)
    supported_winrm_args.update(internal_kwarg_mask)
    passed_winrm_args = set(
        [v.replace("ansible_winrm_", "") for v in self.get_option("_extras")]
    )
    unsupported_args = passed_winrm_args.difference(supported_winrm_args)

    # warn for kwargs unsupported by the installed version of pywinrm
    for arg in unsupported_args:
        display.warning(
            "ansible_winrm_{0} unsupported by pywinrm (is an up-to-date version of pywinrm installed?)".format(
                arg
            )
        )

    # pass through matching extras, excluding the list we want to treat specially
    for arg in passed_winrm_args.difference(internal_kwarg_mask).intersection(
        supported_winrm_args
    ):
        self._winrm_kwargs[arg] = self.get_option("_extras")["ansible_winrm_%s" % arg]


# Traceback (TypeError)
[ansible@myhost /]$ ansible -vvvvv WindowsAdm -m ping
ansible 2.6.2
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/home/ansible/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /home/ansible/.local/lib/python2.7/site-packages/ansible
executable location = /bin/ansible
python version = 2.7.5 (default, May 31 2018, 09:41:32) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]
Using /etc/ansible/ansible.cfg as config file
Reading vault password file: /home/ansible/.mypass
setting up inventory plugins
Parsed /etc/ansible/hosts inventory source with ini plugin
Loading callback plugin minimal of type stdout, v2.0 from /home/ansible/.local/lib/python2.7/site-packages/ansible/plugins/callback/minimal.pyc
META: ran handlers
Using module_utils file /home/ansible/.local/lib/python2.7/site-packages/ansible/module_utils/basic.py
Using module_utils file /home/ansible/.local/lib/python2.7/site-packages/ansible/module_utils/_text.py
Using module_utils file /home/ansible/.local/lib/python2.7/site-packages/ansible/module_utils/parsing/convert_bool.py
Using module_utils file /home/ansible/.local/lib/python2.7/site-packages/ansible/module_utils/parsing/__init__.py
Using module_utils file /home/ansible/.local/lib/python2.7/site-packages/ansible/module_utils/pycompat24.py
Using module_utils file /home/ansible/.local/lib/python2.7/site-packages/ansible/module_utils/six/__init__.py
Using module file /home/ansible/.local/lib/python2.7/site-packages/ansible/modules/system/ping.py
<win-srv1.dev.local> ESTABLISH WINRM CONNECTION FOR USER: user@DEV.LOCAL on PORT 5986 TO win-srv1.dev.local
checking if winrm_host win-srv1.dev.local is an IPv6 address
creating Kerberos CC at /tmp/tmpxcvwNW
calling kinit with pexpect for principal user@DEV.LOCAL
Exception AttributeError: "'spawn' object has no attribute 'closed'" in <bound method spawn.__del__ of <pexpect.spawn object at 0x7fbba0630a90>> ignored
The full traceback is:
Traceback (most recent call last):
File "/home/ansible/.local/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 138, in run
res = self._execute()
File "/home/ansible/.local/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 576, in _execute
result = self._handler.run(task_vars=variables)
File "/home/ansible/.local/lib/python2.7/site-packages/ansible/plugins/action/normal.py", line 46, in run
result = merge_hash(result, self._execute_module(task_vars=task_vars, wrap_async=wrap_async))
File "/home/ansible/.local/lib/python2.7/site-packages/ansible/plugins/action/__init__.py", line 853, in _execute_module
res = self._low_level_execute_command(cmd, sudoable=sudoable, in_data=in_data)
File "/home/ansible/.local/lib/python2.7/site-packages/ansible/plugins/action/__init__.py", line 960, in _low_level_execute_command
rc, stdout, stderr = self._connection.exec_command(cmd, in_data=in_data, sudoable=sudoable)
File "/home/ansible/.local/lib/python2.7/site-packages/ansible/plugins/connection/winrm.py", line 513, in exec_command
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
File "/home/ansible/.local/lib/python2.7/site-packages/ansible/plugins/connection/__init__.py", line 38, in wrapped
self._connect()
File "/home/ansible/.local/lib/python2.7/site-packages/ansible/plugins/connection/winrm.py", line 482, in _connect
self.protocol = self._winrm_connect()
File "/home/ansible/.local/lib/python2.7/site-packages/ansible/plugins/connection/winrm.py", line 375, in _winrm_connect
self._kerb_auth(self._winrm_user, self._winrm_pass)
File "/home/ansible/.local/lib/python2.7/site-packages/ansible/plugins/connection/winrm.py", line 296, in _kerb_auth
env=krb5env, echo=False)
TypeError: __init__() got an unexpected keyword argument 'echo'

win-srv1.dev.local | FAILED! => {
"msg": "Unexpected failure during module execution.",
"stdout": ""
}

# Fixed code
def _build_winrm_kwargs(self):
    # this used to be in set_options, as win_reboot needs to be able to
    # override the conn timeout, we need to be able to build the args
    # after setting individual options. This is called by _connect before
    # starting the WinRM connection
    self._winrm_host = self.get_option("remote_addr")
    self._winrm_user = self.get_option("remote_user")
    self._winrm_pass = self._play_context.password

    self._become_method = self._play_context.become_method
    self._become_user = self._play_context.become_user
    self._become_pass = self._play_context.become_pass

    self._winrm_port = self.get_option("port")

    self._winrm_scheme = self.get_option("scheme")
    # old behaviour, scheme should default to http if not set and the port
    # is 5985 otherwise https
    if self._winrm_scheme is None:
        self._winrm_scheme = "http" if self._winrm_port == 5985 else "https"

    self._winrm_path = self.get_option("path")
    self._kinit_cmd = self.get_option("kerberos_command")
    self._winrm_transport = self.get_option("transport")
    self._winrm_connection_timeout = self.get_option("connection_timeout")

    if hasattr(winrm, "FEATURE_SUPPORTED_AUTHTYPES"):
        self._winrm_supported_authtypes = set(winrm.FEATURE_SUPPORTED_AUTHTYPES)
    else:
        # for legacy versions of pywinrm, use the values we know are supported
        self._winrm_supported_authtypes = set(["plaintext", "ssl", "kerberos"])

    # calculate transport if needed
    if self._winrm_transport is None or self._winrm_transport[0] is None:
        # TODO: figure out what we want to do with auto-transport selection in the face of NTLM/Kerb/CredSSP/Cert/Basic
        transport_selector = ["ssl"] if self._winrm_scheme == "https" else ["plaintext"]

        if HAVE_KERBEROS and (self._winrm_user and "@" in self._winrm_user):
            self._winrm_transport = ["kerberos"] + transport_selector
        else:
            self._winrm_transport = transport_selector

    unsupported_transports = set(self._winrm_transport).difference(
        self._winrm_supported_authtypes
    )

    if unsupported_transports:
        raise AnsibleError(
            "The installed version of WinRM does not support transport(s) %s"
            % to_native(list(unsupported_transports), nonstring="simplerepr")
        )

    # if kerberos is among our transports and there's a password specified, we're managing the tickets
    kinit_mode = self.get_option("kerberos_mode")
    if kinit_mode is None:
        # HACK: ideally, remove multi-transport stuff
        self._kerb_managed = "kerberos" in self._winrm_transport and (
            self._winrm_pass is not None and self._winrm_pass != ""
        )
    elif kinit_mode == "managed":
        self._kerb_managed = True
    elif kinit_mode == "manual":
        self._kerb_managed = False

    # arg names we're going passing directly
    internal_kwarg_mask = set(
        [
            "self",
            "endpoint",
            "transport",
            "username",
            "password",
            "scheme",
            "path",
            "kinit_mode",
            "kinit_cmd",
        ]
    )

    self._winrm_kwargs = dict(username=self._winrm_user, password=self._winrm_pass)
    argspec = getargspec(Protocol.__init__)
    supported_winrm_args = set(argspec.args)
    supported_winrm_args.update(internal_kwarg_mask)
    passed_winrm_args = set(
        [v.replace("ansible_winrm_", "") for v in self.get_option("_extras")]
    )
    unsupported_args = passed_winrm_args.difference(supported_winrm_args)

    # warn for kwargs unsupported by the installed version of pywinrm
    for arg in unsupported_args:
        display.warning(
            "ansible_winrm_{0} unsupported by pywinrm (is an up-to-date version of pywinrm installed?)".format(
                arg
            )
        )

    # pass through matching extras, excluding the list we want to treat specially
    for arg in passed_winrm_args.difference(internal_kwarg_mask).intersection(
        supported_winrm_args
    ):
        self._winrm_kwargs[arg] = self.get_option("_extras")["ansible_winrm_%s" % arg]