# Buggy code
def put_file(self, in_path, out_path):
    super(Connection, self).put_file(in_path, out_path)
    out_path = self._shell._unquote(out_path)
    display.vvv('PUT "%s" TO "%s"' % (in_path, out_path), host=self._winrm_host)
    if not os.path.exists(to_bytes(in_path, errors="surrogate_or_strict")):
        raise AnsibleFileNotFound(
            'file or module does not exist: "%s"' % to_native(in_path)
        )

    script_template = """
            begin {{
                $path = '{0}'

                $DebugPreference = "Continue"
                $ErrorActionPreference = "Stop"
                Set-StrictMode -Version 2

                $fd = [System.IO.File]::Create($path)

                $sha1 = [System.Security.Cryptography.SHA1CryptoServiceProvider]::Create()

                $bytes = @() #initialize for empty file case
            }}
            process {{
               $bytes = [System.Convert]::FromBase64String($input)
               $sha1.TransformBlock($bytes, 0, $bytes.Length, $bytes, 0) | Out-Null
               $fd.Write($bytes, 0, $bytes.Length)
            }}
            end {{
                $sha1.TransformFinalBlock($bytes, 0, 0) | Out-Null

                $hash = [System.BitConverter]::ToString($sha1.Hash).Replace("-", "").ToLowerInvariant()

                $fd.Close()

                Write-Output "{{""sha1"":""$hash""}}"
            }}
        """

    script = script_template.format(self._shell._escape(out_path))
    cmd_parts = self._shell._encode_script(
        script, as_list=True, strict_mode=False, preserve_rc=False
    )

    result = self._winrm_exec(
        cmd_parts[0],
        cmd_parts[1:],
        stdin_iterator=self._put_file_stdin_iterator(in_path, out_path),
    )
    # TODO: improve error handling
    if result.status_code != 0:
        raise AnsibleError(to_native(result.std_err))

    put_output = json.loads(result.std_out)
    remote_sha1 = put_output.get("sha1")

    if not remote_sha1:
        raise AnsibleError("Remote sha1 was not returned")

    local_sha1 = secure_hash(in_path)

    if not remote_sha1 == local_sha1:
        raise AnsibleError(
            "Remote sha1 hash {0} does not match local hash {1}".format(
                to_native(remote_sha1), to_native(local_sha1)
            )
        )


# Traceback (json.decoder.JSONDecodeError)
Using module file /opt/ansible29/venv/lib/python3.7/site-packages/ansible/modules/windows/win_copy.ps1
Pipelining is enabled.
<MyHost> ESTABLISH WINRM CONNECTION FOR USER: ansi@local on PORT 5986 TO MyHost
calling kinit with pexpect for principal ansi@local
EXEC (via pipeline wrapper)
EXEC (via pipeline wrapper)
<MyHost> PUT "/opt/ansible/projects/roles/winrole/files/script1.ps1" TO "C:\Users\ansi@local\AppData\Local\Temp\ansible-tmp-1593428505.6080594-121788640719337\source"
EXEC (via pipeline wrapper)
The full traceback is:
Traceback (most recent call last):
File "/opt/ansible29/venv/lib/python3.7/site-packages/ansible/executor/task_executor.py", line 112, in run
item_results = self._run_loop(items)
File "/opt/ansible29/venv/lib/python3.7/site-packages/ansible/executor/task_executor.py", line 366, in _run_loop
res = self._execute(variables=task_vars)
File "/opt/ansible29/venv/lib/python3.7/site-packages/ansible/executor/task_executor.py", line 645, in _execute
result = self._handler.run(task_vars=variables)
File "/opt/ansible29/venv/lib/python3.7/site-packages/ansible/plugins/action/win_copy.py", line 501, in run
task_vars, self._connection._shell.tmpdir, backup))
File "/opt/ansible29/venv/lib/python3.7/site-packages/ansible/plugins/action/win_copy.py", line 270, in _copy_single_file
self._transfer_file(local_file, tmp_src)
File "/opt/ansible29/venv/lib/python3.7/site-packages/ansible/plugins/action/__init__.py", line 430, in _transfer_file
self._connection.put_file(local_path, remote_path)
File "/opt/ansible29/venv/lib/python3.7/site-packages/ansible/plugins/connection/winrm.py", line 624, in put_file
put_output = json.loads(result.std_out)
File "/opt/ansible29/embedded/lib/python3.7/json/__init__.py", line 348, in loads
return _default_decoder.decode(s)
File "/opt/ansible29/embedded/lib/python3.7/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/opt/ansible29/embedded/lib/python3.7/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
fatal: [MyHost]: FAILED! => {
"msg": "Unexpected failure during module execution.",
"stdout": ""

# Fixed code
def put_file(self, in_path, out_path):
    super(Connection, self).put_file(in_path, out_path)
    out_path = self._shell._unquote(out_path)
    display.vvv('PUT "%s" TO "%s"' % (in_path, out_path), host=self._winrm_host)
    if not os.path.exists(to_bytes(in_path, errors="surrogate_or_strict")):
        raise AnsibleFileNotFound(
            'file or module does not exist: "%s"' % to_native(in_path)
        )

    script_template = """
            begin {{
                $path = '{0}'

                $DebugPreference = "Continue"
                $ErrorActionPreference = "Stop"
                Set-StrictMode -Version 2

                $fd = [System.IO.File]::Create($path)

                $sha1 = [System.Security.Cryptography.SHA1CryptoServiceProvider]::Create()

                $bytes = @() #initialize for empty file case
            }}
            process {{
               $bytes = [System.Convert]::FromBase64String($input)
               $sha1.TransformBlock($bytes, 0, $bytes.Length, $bytes, 0) | Out-Null
               $fd.Write($bytes, 0, $bytes.Length)
            }}
            end {{
                $sha1.TransformFinalBlock($bytes, 0, 0) | Out-Null

                $hash = [System.BitConverter]::ToString($sha1.Hash).Replace("-", "").ToLowerInvariant()

                $fd.Close()

                Write-Output "{{""sha1"":""$hash""}}"
            }}
        """

    script = script_template.format(self._shell._escape(out_path))
    cmd_parts = self._shell._encode_script(
        script, as_list=True, strict_mode=False, preserve_rc=False
    )

    result = self._winrm_exec(
        cmd_parts[0],
        cmd_parts[1:],
        stdin_iterator=self._put_file_stdin_iterator(in_path, out_path),
    )
    # TODO: improve error handling
    if result.status_code != 0:
        raise AnsibleError(to_native(result.std_err))

    try:
        put_output = json.loads(result.std_out)
    except ValueError:
        # stdout does not contain a valid response
        stderr = to_bytes(result.std_err, encoding="utf-8")
        if stderr.startswith(b"#< CLIXML"):
            stderr = _parse_clixml(stderr)
        raise AnsibleError(
            "winrm put_file failed; \nstdout: %s\nstderr %s"
            % (to_native(result.std_out), to_native(stderr))
        )

    remote_sha1 = put_output.get("sha1")
    if not remote_sha1:
        raise AnsibleError("Remote sha1 was not returned")

    local_sha1 = secure_hash(in_path)

    if not remote_sha1 == local_sha1:
        raise AnsibleError(
            "Remote sha1 hash {0} does not match local hash {1}".format(
                to_native(remote_sha1), to_native(local_sha1)
            )
        )