Pass multiple lines(through stdin) from batch to powershell

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
lockedscope
Posts: 31
Joined: 12 Jun 2020 10:38

Pass multiple lines(through stdin) from batch to powershell

#1 Post by lockedscope » 18 Jun 2020 11:30

In the following i try to pass multi-line string to powershell or a powershell script(test.ps1) but it does not work.
Echo multi-line string does not work, but typing multi-line file works.
Why, how could i achieve it with echo? :?:

Code: Select all

setlocal enableDelayedExpansion

(set \n=^
%=DONT REMOVE THIS=%
)
for /f %%G in ("abc!\n!xyz!\n!") do echo Line: %%G
echo ----

rem Passing multiple lines from batch "echo" to openssl does not work
echo abc!\n!xyz!\n! | openssl base64
rem decode (-d) passed string
echo abc!\n!xyz!\n! | openssl base64 | openssl base64 -d

rem Passing multiple lines from batch "echo" to powershell script does not work
echo abc!\n!exit!\n! | Powershell.exe -Noprofile -File test.ps1 

rem Passing multiple lines from batch "echo" to powershell does not work
echo abc!\n!exit!\n! | Powershell.exe -Noprofile "openssl base64 | openssl base64 -d"

rem Passing multiple lines from batch "type" to powershell works
echo abc!\n!xyz!\n! > lines.txt
type lines.txt
type lines.txt | Powershell.exe -Noprofile "openssl base64"
type lines.txt | Powershell.exe -Noprofile "openssl base64 | openssl base64 -d"

Powershell.exe -Noprofile "echo abc`nexit`n" | Powershell.exe -Noprofile "openssl base64 | openssl base64 -d"
Powershell.exe -Noprofile "echo abc`rexit`r" | Powershell.exe -Noprofile "openssl base64 | openssl base64 -d"

Code: Select all

# test.ps1
# $s=[Console]::In.ReadLine();

# Read further characters
while (($c=[Console]::In.Read()) -ne -1) {
  write-host ([char]$c) -nonewline
}

Code: Select all

# Alternative test.ps1
param(
    [parameter(ValueFromPipeline)]$string
)
echo "string value $string"
# Edit: added if statement
if($string){
    $in = "$string"
}else{
    $in = read-host -prompt "input"
}

Write-Host Result $in


Last edited by lockedscope on 18 Jun 2020 11:57, edited 1 time in total.

Aacini
Expert
Posts: 1926
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Pass multiple lines(through stdin) from batch to powershell

#2 Post by Aacini » 18 Jun 2020 11:35

Try:

Code: Select all

(
echo abc
echo exit
) | Powershell.exe -Noprofile -File test.ps1 
Antonio

lockedscope
Posts: 31
Joined: 12 Jun 2020 10:38

Re: Pass multiple lines(through stdin) from batch to powershell

#3 Post by lockedscope » 18 Jun 2020 11:52

It works, thanks
Aacini wrote:
18 Jun 2020 11:35
Try:

Code: Select all

(
echo abc
echo exit
) | Powershell.exe -Noprofile -File test.ps1 
Antonio
So insights from you, i remembered the alternative new line and it worked too

Code: Select all

set \n=^&echo.
echo abc!\n!xyz!\n! | openssl base64
echo abc%\n%exit1%\n% | Powershell.exe -Noprofile -File test.ps1 
echo abc!\n!exit2!\n! | Powershell.exe -Noprofile -File test.ps1 
I think that the usual new line could not be passed to powershell, any way possible to pass it? :?: some escaping etc...

lockedscope
Posts: 31
Joined: 12 Jun 2020 10:38

Re: Pass multiple lines(through stdin) from batch to powershell

#4 Post by lockedscope » 19 Jun 2020 10:18

Actually echo works fine when writing multiline string to output or redirecting output to file but it does not when piping.
But it is not related to piping itself because commands like "type" could pipe multiline string to "for..findstr".
So, string is in parenthesis with echo command as its argument and it will be modified but this does not apply to "type" command, it does not carry the string as an argument but gets from file.

This phenomenon was already explored ;
The <BATCH COMMAND> will be modified if it's inside a parenthesis block.

(
echo one %%cmdcmdline%%
echo two
) | more
Called as C:\Windows\system32\cmd.exe /S /D /c" ( echo one %cmdcmdline% & echo two )", all newlines are changed to & operator.
https://stackoverflow.com/questions/819 ... ck-of-code

Phase 5.3) Pipe processing: Only if commands are on either side of a pipe
Each side of the pipe is processed independently and asynchronously.

If command is internal to cmd.exe, or it is a batch file, or if it is a parenthesized command block, then it is executed in a new cmd.exe thread via %comspec% /S /D /c" commandBlock", so the command block gets a phase restart, but this time in command line mode.
If a parenthesized command block, then all <LF> with a command before and after are converted to <space>&. Other <LF> are stripped.
This is the end of processing for the pipe commands.
See Why does delayed expansion fail when inside a piped block of code? for more about pipe parsing and processing
https://stackoverflow.com/questions/409 ... 33#4095133

jeb
Expert
Posts: 1058
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Pass multiple lines(through stdin) from batch to powershell

#5 Post by jeb » 22 Jun 2020 00:38

Hi lockedscope,

you found already the relevant posts on SO.
Pipes (mostly) creates a child cmd.exe instance on both sides.
The command itself will be executed in the child instance, but the first expansion occurs in the parent instance.

The parent instance will use the percent expansion, but the delayed expansion only occurs when the expression is simple!
And in the child instance the next percent expansion occurs and the parsing fails when there are "raw" line feeds.

Therefore a simple example to show how to create two lines with pipes.

Code: Select all

@echo off
setlocal enableDelayedExpansion
(set \n=^
%=DONT REMOVE THIS=%
)
set "nlm=^^!\n!!\n!"

echo one%%nlm%%two | findstr /n "^"
Obviously the solution of Aacini is much simpler and easier to understand.

Post Reply