If I pass an IF statement through PowerShell's Invoke-Expression
, the command appears to be running and completing, but then it appears that the output is being evaluated as a new command instead of being returned to PowerShell. Three examples:
Invoke-Expression 'echo "hi"'
(No IF statement)Normal Output: hi
Invoke-Expression 'cmd /c IF exist C:\Windows (echo "hi")'
Error on Output: 'hi' is not recognized as an internal or external command, operable program or batch file.
Invoke-Expression 'cmd /c IF exist C:\Windows (query user)'
Error on Output:
'" USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME"' is not recognized as an internal or external command, operable program or batch file.
What's the best way to run a command-line IF statement from PowerShell and be able to read its output? I tried Start-Process
but cannot figure out for the life of me how to read its output. Tried a System.Diagnostics.ProcessStartInfo
object copied from another StackOverflow post, but no luck there either.
Because people are bound to ask: The reason why I'm passing this through cmd in the first place is because this entire code block needs to be passed through Invoke-Command
to a remote machine and cmd has folder/file access to computers on its network while PowerShell does not.
Your immediate problem is unrelated to the use of Invoke-Expression
, which should generally be avoided:
cmd /c IF exist C:\Windows (echo "hi") # WRONG
is interpreted by PowerShell first, up front, and (echo "hi")
is the same as (Write-Output "hi")
, which PowerShell expands (interpolates) to the command's output, a string with content hi
.
The - broken - command line that cmd
exe ends up seeing is the following, which explains the error message:
cmd /c IF exist C:\Windows hi
For an overview of how PowerShell parses unquoted command-line arguments, see this answer.
There are several ways to fix that problem, appropriate in different scenarios:
# Single-quoting - passed as-is.
cmd /c 'IF exist C:\Windows (echo "hi")'
# Double-quoting - PowerShell would still expand $-prefixed tokens up front.
cmd /c "IF exist C:\Windows (echo `"hi`")"
#`# The stop-parsing symbol, --%, prevents PowerShell from parsing subsequent arguments,
# with the exception of cmd-style environment-variable references (%FOO%)
cmd /c --% IF exist C:\Windows (echo "hi")
Now, with Invoke-Expression
you'd have to add escape those quotes due to having to specify them as part of a string, but, as mentioned in the comments, there is rarely a need for Invoke-Expression
, and it is neither needed here, nor would I expect it to help with the "double hop" authentication problem you describe in a comment.
To address the latter, try this answer, which uses explicitly passed credentials to establish an auxiliary drive mapping on the remote machine.