简体   繁体   中英

Running PowerShell from another shell with Tee

I'd like to learn to execute a PowerShell command from another shell or language, eg Python os.system() . What I want to achieve is the following:

  1. Execute the PowerShell command
  2. Tee the output to both the console and a file
  3. Return the command exit code

I think this gives an idea of what I would like to achieve, assuming to use cmd.exe as the caller environmnet:

powershell -NoProfile -command "& { cat foo.txt  | Tee-Object ps-log.txt; exit $LASTEXITCODE }"
echo %errorlevel%

There are some problems here. First, I cannot use quotations in the command, eg :

powershell -NoProfile -command "& { cat `"foo bar.txt`"  | Tee-Object ps-log.txt; exit $LASTEXITCODE }"

The cat argument seems to be passed unquoted and so cat looks for a 'bar.txt' parameter.

I think $LASTEXITCODE is expanded soon, that is before cat is executed.

& is inconvenient to use, because it does not accept a single command line string including arguments. An alternative to & is iex , however I cannot use it from cmd.exe. In fact:

powershell  -NoProfile -command  {iex cat  foo.txt}

returns:

iex cat foo.txt

From cmd.exe , use the following ( -c is short for -Command ):

C:\>powershell -NoProfile -c "Get-Content \"foo bar.txt\" | Tee-Object ps-log.txt; exit -not $?"
  • There's no reason to use & {... } in a string passed to -Command - just use ... instead.

  • Escape embedded " chars. as \" (PowerShell (Core) 7+ also accepts "" ).

  • Since only PowerShell-native commands are involved in the command (on Windows, cat is simply an alias of Get-Content ), $LASTEXITCODE is not set, as it only reflects the exit code of external programs . Instead, the automatic $? variable applies, which is a Boolean that indicates whether any errors were emitted by the commands in the most recently executed pipeline.

    • Negating this value with -not means that $true is converted to $false and $false to $true , and these values are converted to integers for the outside, with $false mapping to 0 and $true to 1 .

Powershell supports single quotes, which saved me in such situations quite a lot of times. The good thing about it: They are unambiguous and easy to read. But mind that variable expansion won't work inside single-quoted strings.

powershell -NoProfile -command "cat 'foo bar.txt' | tee ps-log.txt"

Apart from that, have a look at the useful advice in mklement0's answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM