win_shell - What's the proper way to use a command with a flag in ansible playbook or adhoc command.

4,296 views
Skip to first unread message

marcalfa1

unread,
Oct 11, 2017, 4:32:06 PM10/11/17
to Ansible Project

Trying to "dir /b c:\Temp"  using a playbook or via adhoc and getting the error message below.  It seems to have a problem with "/b" in "Dir /b C:\Temp"



- hosts: all
  gather_facts: yes
  tasks:

   - win_shell: dir /b C:\Temp


FAILED! => {"changed": true, "cmd": "dir /b C:\\Temp", "delta": "0:00:00.839042", "end": "2017-10-11 08:22:02.820065", "failed": true, "rc": 1, "start": "2017-10-11 08:22:01.981022", "stderr": "dir : Cannot find path 'C:\\b' because it does not exist.\r\nAt line:1 char:65\r\n+ [Console]::InputEncoding = New-Object Text.UTF8Encoding $false; dir /b \r\nC:\\Temp\r\n+                                                                 \r\n~~~~~~~~~~~~~~\r\n    + CategoryInfo          : ObjectNotFound: (C:\\b:String) [Get-ChildItem], I \r\n   temNotFoundException\r\n    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetCh \r\n   ildItemCommand", "stderr_lines": ["dir : Cannot find path 'C:\\b' because it does not exist.", "At line:1 char:65", "+ [Console]::InputEncoding = New-Object Text.UTF8Encoding $false; dir /b ", "C:\\Temp", "+                                                                 ", "~~~~~~~~~~~~~~", "    + CategoryInfo          : ObjectNotFound: (C:\\b:String) [Get-ChildItem], I ", "   temNotFoundException", "    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetCh ", "   ildItemCommand"], "stdout": "", "stdout_lines": []}


ansible -i poc-win all -m raw -a "dir /b C:\Temp"
 | FAILED | rc=1 >>
dir : Cannot find path 'C:\b' because it does not exist.
At line:1 char:1
+ dir /b C:\Temp
+ ~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\b:String) [Get-ChildItem], I
   temNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetCh
   ildItemCommand


 ansible -i poc-win all -m win_shell -a "dir /b C:\Temp"
 | FAILED | rc=1 >>
dir : Cannot find path 'C:\b' because it does not exist.
At line:1 char:65
+ [Console]::InputEncoding = New-Object Text.UTF8Encoding $false; dir /b
C:\Temp
+
~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\b:String) [Get-ChildItem], I
   temNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetCh
   ildItemCommand


Jordan Borean

unread,
Oct 11, 2017, 5:02:30 PM10/11/17
to Ansible Project
Hi

The win_shell module actually executes a command in the PowerShell where dir is an alias for Get-ChildItem. Get-ChildItem (and other PS cmdlets) do not have parameters or switches in the form of /* which is why you are getting this error. You can either change your task to use the PowerShell cmdlet format or change the shell to cmd. You can also use win_find if you want to have more advanced filters or search recursively so have a look at that if you want to filter on the files.

- name: using native PS cmdlet
  win_shell
: Get-ChildItem -Path C:\Temp | ForEach-Object { $_.Name }

- name: change shell to cmd
  win_shell
: dir /b c:\temp
  args
:
    executable
: cmd

Here is the output of both of those tasks


In your case I would go with the cmd option as it is faster (5s as opening Powershell takes time) and less verbose but the PS option is good if you need to save variables or do something with the data before sending it back to Ansible.

Thanks

Jordan



marcalfa1

unread,
Oct 11, 2017, 8:04:32 PM10/11/17
to Ansible Project

Jordan,

Thanks a million. I was able to get the output I'm looking for. Now that have the list of files in my C:\Temp, how do I fetch those files to my ansible controller host?  Here's an example I have so far but failing at one section.


- hosts: all
  gather_facts: yes
  tasks:

   - win_shell: dir /b C:\Temp\*.tar
     args:
        executable: cmd
     register: results
   - debug:
       var: results.stdout_lines

   - name: get the files
     fetch:
       src: "C:/Temp/{{ item }}"
       dest: /home/vagrant/win-script-result/
       flat: yes
       with_items: "{{ results.stdout_lines }}"





TASK [Gathering Facts] **************************************************************************************************************************************************************************************************************************************************************************************************
ok: [SV1]
ok: [SV2]

TASK [win_shell] ********************************************************************************************************************************************************************************************************************************************************************************************************
changed: [SV1]
changed: [SV2]

TASK [debug] ************************************************************************************************************************************************************************************************************************************************************************************************************
ok: [SV1] => {
    "results.stdout_lines": [
        "1709051418.tar",
        "1709051525.tar",
        "1709052115.tar"
    ]
}
ok: [SV2] => {
    "results.stdout_lines": [
        "1709051421.tar",
        "1709051527.tar",
        "1709052107.tar"
    ]
}

TASK [get the files] ****************************************************************************************************************************************************************************************************************************************************************************************************
fatal: [SV1]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'item' is undefined\n\nThe error appears to have been in '/home/vagrant/ansible/find-copy-test.yml': line 12, column 6, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n   - name: get the files\n     ^ here\n"}
fatal: [SV2]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'item' is undefined\n\nThe error appears to have been in '/home/vagrant/ansible/find-copy-test.yml': line 12, column 6, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n   - name: get the files\n     ^ here\n"}
        to retry, use: --limit @/home/vagrant/ansible/find-copy-test.retry

Jordan Borean

unread,
Oct 11, 2017, 9:13:28 PM10/11/17
to Ansible Project
Your indent for with_items is incorrect, it should be set on the task level and not module level, so

- name: get the files
  fetch
:
    src
: "C:/Temp/{{ item }}"
    dest
: /home/vagrant/win-script-result/
    flat
: yes
  with_items
: "{{ results.stdout_lines }}"

I would also highly recommend swapping over to the win_find module instead of running that command. It gives you more control over what to find as you can add multiple regex strings to search and gives you room to expand in the future. This is what it would look like;

- name: find tar files
  win_find
:
    paths
: C:\temp
    file_type
: file
    patterns
: '*.tar'
 
register: tar_files


- name: fetch tar files
  fetch
:
    src
: '{{ item.path }}'
    dest
: /home/vagrant/win-script-result/
    flat
: yes
  with_items
: '{{ tar_files.files }}'

Both paths and patterns can take in a list so you can specify multiple paths and patterns instead of running separate tasks. It also gives you the ability to use regex if you really feel like hurting yourself :)

Thanks

Jordan

marcalfa1

unread,
Oct 12, 2017, 10:37:31 PM10/12/17
to Ansible Project
Jordan,

The solutions you've provided worked out fine.  I ended up using win_shell module simply because I was not able to pass *%computername%* variable in win_find patterns. I'm a beginner and ready to tackle regex :-)

I really appreciate your help. Also, by any chance the values in results.stdout_lines can be used in combication with the archive module to tar the files in result?

Thanks in advance.


- hosts: all
  gather_facts: yes
  tasks:

   - win_shell: dir /b C:\Temp\*%computername%*

     args:
        executable: cmd
     register: results
   - debug:
       var: results.stdout_lines

   - name: get the files
     fetch:
       src: "C:/Temp/{{ item }}"
       dest: /home/vagrant/win-script-result/
       flat: yes
     with_items: "{{ results.stdout_lines }}"

J Hawkesworth

unread,
Oct 13, 2017, 3:46:28 AM10/13/17
to Ansible Project
For win_find, you can probably use a paths like 

   paths: "C:\\Temp\\*{{ansible_hostname}}*"


or if you need to use the hostname as defined in your inventory

   paths: "C:\\Temp\\*{{inventory_hostname}}*"

One of the nice things about win_find is it will give you a better structured set of results than using win_shell and looping through the results.stdout_lines

fetch is intended to be tolerant of files being missing, so it won't choke if you pass it the results.stdout_lines as items.

However as you want to use archive to tar up the files you have fetched, win_find should probably give you a better quality list.

You can use archive (assuming it does what you want) by delegating to localhost, like this (untested)

- name: archive fetched files
  archive
:
     path
: /home/vagrant/win-script-result/
     dest
: /home/vagrant/results.tgz
  delegate_to
: localhost



Hope this helps,

Jon

J Hawkesworth

unread,
Oct 13, 2017, 3:49:24 AM10/13/17
to Ansible Project
Oh, meant to say ansible_hostname and inventory_hostname are documented here: http://docs.ansible.com/ansible/latest/playbooks_variables.html
Reply all
Reply to author
Forward
0 new messages