Paavo
Paavo

Reputation: 21

Mapping a Network Drive on a Windows Guest using Ansible

I'm trying to automate some tasks on Windows guests using Ansible, and I'm running into some issues mapping a network drive.

What I'm trying to do is map the drive, do something to it (in my example here, I just try to list the files), and then unmap it.

When I run Ansible, the output suggests that the shared drive was mapped successfully, but listing the files and unmapping both result in errors that state that the drive doesn't exist. ("A drive with the name 'K' does not exist.")

When I login to the Windows guest after running Ansible, the drive is mapped.

If I run Ansible while I am logged in the guest, the drive only becomes visible after I logout and log back in again. The script I use to mount the drive also creates a file on the guest for debugging purposes, and the file does appear even when I'm logged in. I don't need to logout and back in again for it to become visible. So it seems only the network drive mapping requires a logout and login to take effect.

I also tried "net use" to map the drive, and the results were the same.

My Ansible playbook looks like this. (I have left out some sensitive parts.)

  tasks:
      - name: Mount share
        script: scripts/mount.ps1 {{ share }}
      - name: Test
        script: scripts/test.ps1
        register: test
      - name: Test stdout
        debug: msg="{{ test.stdout }}"
      - name: Test stderr
        debug: msg="{{ test.stderr }}"
      - name: Umount share
        script: scripts/umount.ps1

mount.ps1.

param([string]$share)
$share | Out-File c:\ansible-test\debug.txt
New-PSDrive -Name "K" -PSProvider FileSystem -Root "$share" -Persist

test.ps1

Get-ChildItem K:\

umount.ps1

Remove-PSDrive "K"

Upvotes: 2

Views: 5757

Answers (2)

Abhishek Kulkarni
Abhishek Kulkarni

Reputation: 3828

After reading so many articles, stackoverflow links, I was unable to map network drive on windows because of multiple failure.

Finally, I wrote a custom ansible playbook which is a very very raw workaround -

---

- hosts: "{{hostname}}"
  name: "MOUNT SMB SHARE"
  gather_facts: no
  vars:
    already_mounted: false
    drive_matched: false
    drive_letter: "{{drive}}:"
    share_path: '\\{{fs}}\{{share}}'
  tasks:
    - name: Delete status file if exists
      file:
        path: c:\\__run_status
        state: absent
      ignore_errors: yes

    - name: Delete map_drive.ps1 if exists
      file:
        path: c:\\map_drive.ps1
        state: absent
      ignore_errors: yes

    - name: Delete run.bat if exists
      file:
        path: c:\\run.bat
        state: absent
      ignore_errors: yes

    - name: Delete task if exists
      win_shell: schtasks.exe /DELETE /TN MAPDRIVE /F
      register: command_output
      ignore_errors: yes

    - name: smb-mapping command
      set_fact:
        cmd1: New-SmbMapping -LocalPath {{drive_letter}} -Persistent 1
        cmd2: -RemotePath {{share_path}} -UserName {{username}} -Password {{password}}

    - name: Write powershell script
      local_action:
        module: copy
        content: |
          Enable-PSRemoting
          if (Get-PSDrive {{drive}} -ErrorAction SilentlyContinue) {
              Write-Host "Delete drive {{drive_letter}} which is already in use."
              net use {{drive_letter}} /delete
          }
          {{cmd1}} {{cmd2}}
        dest: /tmp/map_drive.ps1

    - name: write wrapper batch
      local_action:
        module: copy
        content: |
          powershell.exe c:\\map_drive.ps1 >> c:\\__run_status
          echo "FINISH" >> c:\\__run_status
        dest: /tmp/run.bat

    - name: Powershell script to map network drive
      win_copy: src=/tmp/map_drive.ps1 dest=c:\\map_drive.ps1
      register: result
      until: result is success
      retries: 3
      delay: 30

    - name: Batch script to run map network drive
      win_copy: src=/tmp/run.bat dest=c:\\run.bat
      register: result
      until: result is success
      retries: 3
      delay: 30

    - name: Register scheduled task commad args
      set_fact:
        cmd1: "Register-ScheduledTask 'MAPDRIVE' -InputObject"
        cmd2: $(New-ScheduledTask -Action $(New-ScheduledTaskAction -Execute c:\run.bat)
        cmd3: -Trigger $(New-ScheduledTaskTrigger -AtStartup))
        cmd4: "-User {{win_user}} -Password {{win_pass}}"

    - name: Register scheduled task commad
      set_fact:
        cmd: "powershell.exe {{cmd1}} {{cmd2}} {{cmd3}} {{cmd4}}"

    - name: create batch script
      local_action:
        module: copy
        content: "{{ cmd }}"
        dest: /tmp/register_task.bat

    - name: Wait for the windows server is able to connect
      wait_for_connection:
        connect_timeout: 120
        delay: 2

    - name: Copying batch to windows guest
      win_copy: src=/tmp/register_task.bat dest=c:\\register_task.bat
      register: result
      until: result is success
      retries: 3
      delay: 30

    - name: Pring command output
      debug:
        msg: "{{command_output.stdout}}"

    - name: Register scheduled task
      win_shell: C:\register_task.bat
      register: command_output

    - name: Debug
      debug:
        msg: "{{command_output}}"

    - name: Start freesshd scheduled task
      win_shell: powershell.exe "& Start-ScheduledTask -TaskName 'MAPDRIVE'"
      register: command_output

    - name: Query task
      win_shell: "schtasks.exe /QUERY /TN MAPDRIVE"
      register: command_output

    - name: Pring command output
      debug:
        msg: "{{command_output.stdout}}"

    - name: Check if map_drive.ps1 execution completed
      win_shell: type C:\\__run_status
      register: result
      until: result.stdout.find('FINISH') != -1
      retries: 10
      delay: 30

    - name: Delete task
      win_shell: schtasks.exe /DELETE /TN MAPDRIVE /F
      register: command_output

    - name: Pring command output
      debug:
        msg: "{{command_output.stdout}}"

Upvotes: 0

Raath
Raath

Reputation: 719

Unfortunately this is down the way Ansible communicates with windows. I've had similar issues where commands and package installation didn't work as expected.

When Ansible communicates over WinRM to the windows box it initiates a batch connection, not a full session. Mapping drives is one of those tasks that requires a full session, but each task that Ansible runs creates it's own batch connection so when you map a drive as soon as it disconnects, you loose that mapping because there is no actual user to register it too.

The only work around you have here is to create a .ps1 to map the drive then use Invoke-Command.

Here is my work around :

- name: map drive and run a task
  script: files/mapdrive.ps1 -network_password "{{ network_password }" -command_to_run "{ Copy-Item Y:\file_to_copy.txt C:\Some\Were }"

and my ps1 looks like this :

param(
  $network_password,
  $command_to_run
)
$PWord = ConvertTo-SecureString $network_password -AsPlainText -Force
$myCreds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "domain\user",$PWord
New-PSDrive -Name "Y" -PSProvider "FileSystem" -Root "\\remoteserver\share" -Credential $myCreds
Invoke-Command -ScriptBlock $command_to_run

Apparently future releases of Ansible will employ a form of "become" which will allow these persistent sessions making this type of task a lot easier, but that could be a couple of years away and at least 2 or 3 releases ahead.

Upvotes: 3

Related Questions