Windows – Has anyone solved the double-hop issue with Ansible and Windows clients

ansiblepowershellwindowswinrm

My situation: I have an Ansible server, a Tower server, a Windows file server, and a Windows client. Through Ansible, I want to tell the Windows client to copy some files from the Windows file server. After having trouble finding a playbook module that would allow me to copy files from a remote host to a client machine, I decided to try a series of different Powershell scripts and cmdlets to perform the simple file copy.

I appear to be running into the double hop problem and since an Ansible / Linux server is the originating machine in this scenario- and I don't have control of that machine- I was wondering if anyone has solved this problem and managed to get scripts to get past the double hop. Alternatively, if anyone knows of an Ansible module that can copy files from a remote host to a client host, that would be of interest, too. If I need to submit a ticket for the Ansible owners to do something, or if I need to do something, or if I should give up, whatever the case, thanks for your time!

Best Answer

While this is an absolute hack, and I'm sure you've already moved on from this problem, one workaround is to create a scheduled task (using the Windows schtasks command) and execute it immediately to perform the copy. The scheduled task will run in the proper context and be able to copy from the server without encountering the double-hop issue, because it originates from the client machine. I'm sure there's an actual Ansible-level solution to this problem, but this is my current workaround.

Your higher level script can use psutil or something similar to monitor the task and not return until the scheduled task has completed.

Here's an helper script I wrote in Python for accomplishing this:

# run_as_scheduled_task.py
import psutil
import subprocess
import time
import sys

to_match = sys.argv[1]
to_run = ' '.join(sys.argv[2:])
print("Running the following command as immediate scheduled task:")
print(to_run)
print("Will return only once process matching wildcard \"{0}\" is no longer found".format(to_match))

subprocess.call('C:\\Windows\\System32\\schtasks /delete /f /tn "QUICKSCHTASK"', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
subprocess.call('C:\\Windows\\System32\\schtasks /create /tn "QUICKSCHTASK" /tr "{0}" /sc ONCE /st 00:00'.format(to_run), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
subprocess.call('C:\\Windows\\System32\\schtasks /run /tn "QUICKSCHTASK"', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
time.sleep(0.1)

def processDead(proc):
    print("Process is now dead - {0}".format(proc))
    subprocess.call('C:\\Windows\\System32\\schtasks /delete /f /tn "QUICKSCHTASK"', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)

process = None
for proc in psutil.process_iter():
    if to_match in proc.name():
        gone, still_alive = psutil.wait_procs([proc], None, processDead)
        break

You can call this from a higher level script to perform operations and circumvent the double hop. Very hacky, but it works. Example usage of script would be:

start /wait py -3 run_as_scheduled_task.py 'robocopy' 'robocopy SOURCE DEST'

An alternative method is to call psexec on the target machine with the -s flag to use the System account. More information on that here: https://stackoverflow.com/questions/15242248/double-hop-access-to-copy-files-without-credssp