diff --git a/lib/ansible/modules/windows/win_command.ps1 b/lib/ansible/modules/windows/win_command.ps1 index 4570ffc31f..da6b4f62b9 100644 --- a/lib/ansible/modules/windows/win_command.ps1 +++ b/lib/ansible/modules/windows/win_command.ps1 @@ -18,6 +18,7 @@ $raw_command_line = Get-AnsibleParam -obj $params -name "_raw_params" -type "str $chdir = Get-AnsibleParam -obj $params -name "chdir" -type "path" $creates = Get-AnsibleParam -obj $params -name "creates" -type "path" $removes = Get-AnsibleParam -obj $params -name "removes" -type "path" +$stdin = Get-AnsibleParam -obj $params -name "stdin" -type 'str"' $raw_command_line = $raw_command_line.Trim() @@ -34,9 +35,19 @@ If($removes -and -not $(Test-Path -Path $removes)) { Exit-Json @{msg="skipped, since $removes does not exist";cmd=$raw_command_line;changed=$false;skipped=$true;rc=0} } +$command_args = @{ + command = $raw_command_line +} +if ($chdir) { + $command_args['working_directory'] = $chdir +} +if ($stdin) { + $command_args['stdin'] = $stdin +} + $start_datetime = [DateTime]::UtcNow try { - $command_result = Run-Command -command $raw_command_line -working_directory $chdir + $command_result = Run-Command @command_args } catch { $result.changed = $false try { diff --git a/lib/ansible/modules/windows/win_command.py b/lib/ansible/modules/windows/win_command.py index 793f5a0c23..8699015d03 100644 --- a/lib/ansible/modules/windows/win_command.py +++ b/lib/ansible/modules/windows/win_command.py @@ -50,7 +50,11 @@ options: - a path or path filter pattern; when the referenced path B(does not) exist on the target host, the task will be skipped. chdir: description: - - set the specified path as the current working directory before executing a command + - set the specified path as the current working directory before executing a command. + stdin: + description: + - Set the stdin of the command directly to the specified value. + version_added: '2.5' notes: - If you want to run a command through a shell (say you are using C(<), C(>), C(|), etc), you actually want the M(win_shell) module instead. The @@ -73,6 +77,11 @@ EXAMPLES = r''' args: chdir: C:\somedir\ creates: C:\backup\ + +- name: Run an executable and send data to the stdin for the executable + win_command: powershell.exe - + args: + stdin: Write-Host test ''' RETURN = r''' diff --git a/lib/ansible/modules/windows/win_shell.ps1 b/lib/ansible/modules/windows/win_shell.ps1 index e25678d2dc..ee7172c826 100644 --- a/lib/ansible/modules/windows/win_shell.ps1 +++ b/lib/ansible/modules/windows/win_shell.ps1 @@ -46,6 +46,7 @@ $chdir = Get-AnsibleParam -obj $params -name "chdir" -type "path" $executable = Get-AnsibleParam -obj $params -name "executable" -type "path" $creates = Get-AnsibleParam -obj $params -name "creates" -type "path" $removes = Get-AnsibleParam -obj $params -name "removes" -type "path" +$stdin = Get-AnsibleParam -obj $params -name "stdin" -type "str" $raw_command_line = $raw_command_line.Trim() @@ -72,7 +73,11 @@ If(-not $executable -or $executable -eq "powershell") { # Base64 encode the command so we don't have to worry about the various levels of escaping $encoded_command = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($raw_command_line)) - $exec_args = "-noninteractive -encodedcommand $encoded_command" + if ($stdin) { + $exec_args = "-encodedcommand $encoded_command" + } else { + $exec_args = "-noninteractive -encodedcommand $encoded_command" + } } Else { # FUTURE: support arg translation from executable (or executable_args?) to process arguments for arbitrary interpreter? @@ -84,9 +89,19 @@ Else { } $command = "$exec_application $exec_args" +$run_command_arg = @{ + command = $command +} +if ($chdir) { + $run_command_arg['working_directory'] = $chdir +} +if ($stdin) { + $run_command_arg['stdin'] = $stdin +} + $start_datetime = [DateTime]::UtcNow try { - $command_result = Run-Command -command $command -working_directory $chdir + $command_result = Run-Command @run_command_arg } catch { $result.changed = $false try { diff --git a/lib/ansible/modules/windows/win_shell.py b/lib/ansible/modules/windows/win_shell.py index f42fa754b4..4bf5bf818d 100644 --- a/lib/ansible/modules/windows/win_shell.py +++ b/lib/ansible/modules/windows/win_shell.py @@ -53,6 +53,10 @@ options: description: - change the shell used to execute the command (eg, C(cmd)). The target shell must accept a C(/c) parameter followed by the raw command line to be executed. + stdin: + description: + - Set the stdin of the command directly to the specified value. + version_added: '2.5' notes: - If you want to run an executable securely and predictably, it may be better to use the M(win_command) module instead. Best practices when writing @@ -88,6 +92,19 @@ EXAMPLES = r''' args: executable: cmd register: homedir_out + +- name: run multi-lined shell commands + win_shell: | + $value = Test-Path -Path C:\temp + if ($value) { + Remove-Item -Path C:\temp -Force + } + New-Item -Path C:\temp -ItemType Directory + +- name: retrieve the input based on stdin + win_shell: '$string = [Console]::In.ReadToEnd(); Write-Output $string.Trim()' + args: + stdin: Input message ''' RETURN = r''' diff --git a/test/integration/targets/win_command/tasks/main.yml b/test/integration/targets/win_command/tasks/main.yml index b49d19301d..aaa8ea3fb9 100644 --- a/test/integration/targets/win_command/tasks/main.yml +++ b/test/integration/targets/win_command/tasks/main.yml @@ -178,3 +178,18 @@ win_file: path: C:\ansible testing state: absent + +- name: run stdin test + win_command: powershell.exe - + args: + stdin: Write-Host "some input" + register: cmdout + +- name: assert run stdin test + assert: + that: + - cmdout|changed + - cmdout.rc == 0 + - cmdout.stdout_lines|count == 1 + - cmdout.stdout_lines[0] == "some input" + - cmdout.stderr == "" diff --git a/test/integration/targets/win_shell/tasks/main.yml b/test/integration/targets/win_shell/tasks/main.yml index 89d011d8bd..2716b948e3 100644 --- a/test/integration/targets/win_shell/tasks/main.yml +++ b/test/integration/targets/win_shell/tasks/main.yml @@ -188,3 +188,17 @@ - shellout.stdout is search("doneout") - shellout.stderr is search("starterror") - shellout.stderr is search("doneerror") + +- name: run stdin test + win_shell: '$string = [Console]::In.ReadToEnd(); Write-Output $string.Trim()' + args: + stdin: some input + register: shellout + +- name: assert run stdin test + assert: + that: + - shellout|changed + - shellout.rc == 0 + - shellout.stderr == "" + - shellout.stdout == "some input\r\n"