#!powershell #Requires -Module Ansible.ModuleUtils.Legacy #Requires -Module Ansible.ModuleUtils.ArgvParser $ErrorActionPreference = 'Continue' $params = Parse-Args $args $exe = Get-AnsibleParam -obj $params -name "exe" -type "path" -failifempty $true Add-Type -TypeDefinition @' using System.IO; using System.Threading; namespace Ansible.Command { public static class NativeUtil { public static void GetProcessOutput(StreamReader stdoutStream, StreamReader stderrStream, out string stdout, out string stderr) { var sowait = new EventWaitHandle(false, EventResetMode.ManualReset); var sewait = new EventWaitHandle(false, EventResetMode.ManualReset); string so = null, se = null; ThreadPool.QueueUserWorkItem((s)=> { so = stdoutStream.ReadToEnd(); sowait.Set(); }); ThreadPool.QueueUserWorkItem((s) => { se = stderrStream.ReadToEnd(); sewait.Set(); }); foreach(var wh in new WaitHandle[] { sowait, sewait }) wh.WaitOne(); stdout = so; stderr = se; } } } '@ Function Invoke-Process($executable, $arguments) { $proc = New-Object System.Diagnostics.Process $psi = $proc.StartInfo $psi.FileName = $executable $psi.Arguments = $arguments $psi.RedirectStandardOutput = $true $psi.RedirectStandardError = $true $psi.UseShellExecute = $false $proc.Start() > $null # will always return $true for non shell-exec cases $stdout = $stderr = [string] $null [Ansible.Command.NativeUtil]::GetProcessOutput($proc.StandardOutput, $proc.StandardError, [ref] $stdout, [ref] $stderr) > $null $proc.WaitForExit() > $null $actual_args = $stdout.Substring(0, $stdout.Length - 2) -split "`r`n" return $actual_args } $tests = @( @('abc', 'd', 'e'), @('a\\b', 'de fg', 'h'), @('a\"b', 'c', 'd'), @('a\\b c', 'd', 'e'), @('C:\Program Files\file\', 'arg with " quote'), @('ADDLOCAL="a,b,c"', '/s', 'C:\\Double\\Backslash') ) foreach ($expected in $tests) { $joined_string = Argv-ToString -arguments $expected # We can't used CommandLineToArgvW to test this out as it seems to mangle # \, might be something to do with unicode but not sure... $actual = Invoke-Process -executable $exe -arguments $joined_string if ($expected.Count -ne $actual.Count) { $result.actual = $actual -join "`n" $result.expected = $expected -join "`n" Fail-Json -obj $result -message "Actual arg count: $($actual.Count) != Expected arg count: $($expected.Count)" } for ($i = 0; $i -lt $expected.Count; $i++) { $expected_arg = $expected[$i] $actual_arg = $actual[$i] if ($expected_arg -cne $actual_arg) { $result.actual = $actual -join "`n" $result.expected = $expected -join "`n" Fail-Json -obj $result -message "Actual arg: '$actual_arg' != Expected arg: '$expected_arg'" } } } Exit-Json @{ data = 'success' }