0

I have file with the following contents hosted on dropbox: (I know it is not currently calling anything)

function test_echo {

[CmdletBinding()]
param ( 
[Parameter (Position=0,Mandatory = $True, ValueFromPipeline = $True)]
[string]$e
) 

echo $e
}

Is there a way to pipe information into this file before it is downloaded and executed?

ex:

"test" | iwr DropBoxLink | iex

and to make this echo out test

this honestly probably has no practical application, but I found myself wondering if it is possible so thought I'd ask.

I know I could define the string as a variable first and execute it but I just want to know if you can pipe it for principles sake

$testEcho = "string"; iwr DropBoxLink | iex

> string

I am Jakoby
  • 577
  • 4
  • 19
  • 1
    You could download the file, append `"test"` to it and then execute? – Mathias R. Jessen Dec 14 '22 at 16:02
  • 100%. there are definitely a few work arounds, but literally just for the sake of knowing is why I asked this question. I am just really curious – I am Jakoby Dec 14 '22 at 16:04
  • You can add a string argument to a powershell script : https://stackoverflow.com/questions/1293907/how-to-pass-command-line-arguments-to-a-powershell-ps1-file – jdweng Dec 17 '22 at 10:26
  • 2
    This question should be closed in its current status, because it needs more focus and needs a lot of clarification: 1. "Is there a way to pipe information into this file before it is downloaded and executed?" Seriously? You want to insert text into a file that has not been downloaded yet? I highly doubt. Please clarify. 2. With `iwr` you will get a web response status object and the actual file content will be burried in a sub property. Do you want to execute that code? Or do you want to download it into a file and let `iex` execute that file? – stackprotector Dec 17 '22 at 11:11
  • 2
    3. How do you want us to make this whole thing echo "test", if your script is just a function definition and does not echo anything? 4. While your question seems to focus on "piping" a variable to the script invocation, your bounty description does not do that at all? So, what *do* you want? – stackprotector Dec 17 '22 at 11:11
  • 2
    Agree, should be closed as: **`Needs details or clarity`** *This question should include more details and clarify the problem.* (unfortunately as it has a bounty, it can't be closed) – iRon Dec 21 '22 at 11:26

1 Answers1

2
"test" | % -begin { iex (irm $DropBoxUrl) } -process { $_ | test_echo }
  • The above uses a ForEach-Object call's -Begin block to download and evaluate the script (the usual caveats re iex (Invoke-Expression) apply - you should trust the source), which defines the test_echo function contained in the downloaded script.

  • The -Begin script block executes before pipeline input is processed, which means that by the time the -Process script block processes (each) pipeline input object, the test_echo function is already defined.

  • Also note that irm (Invoke-RestMethod) rather than iwr (Invoke-WebRequest) is used, given that you're only interested in the content of the script.

Of course, this doesn't gain you much, as you could simply use two statements, which has the added advantage that all pipeline input (should there be multiple input objects) are handled by a single test_echo invocation:

iex (irm $DropBoxUrl) # Download and effectively dot-source the script.
"test" | test_echo    # Pipe to the script's `test_echo` function.

A general caveat is that if the downloaded script contains an exit statement that is hit during evaluation, the calling shell exits as a whole.

  • Since in effect you need to dot-source the downloaded script in order to make its functions available, the only way to solve the exit problem is to download to a (temporary) file first, and dout-source that.

  • If dot-sourcing isn't needed, calling via the PowerShell CLI (child process) may be an option - see below.

  • GitHub issue #5909 proposes a future enhancement that would allow piping Invoke-WebRequest (iwr) calls to Invoke-Command (icm) for direct-from-the-web downloading and execution, without the exit problem (iwr $DropboxLink | icm).


Note that if your downloaded script were to accept pipeline input directly, you could use [scriptblock]::Create() as follows (Invoke-Expression is not an option, because it doesn't accept pipeline input):

# Assumes that the script located at $DropBoxUrl
# *itself* accepts pipeline input.
# Use . (...) if you want to *dot-source* the script, as 
# Invoke-Expression would implicitly do.
"test" | & ([scriptblock]::Create((irm $DropBoxUrl))

To work around the exit problem, you can call via the CLI and a script block, using pwsh, the PowerShell (Core) 7+ CLI, in this example; use powershell.exe for Windows PowerShell:

# Assumes that the script located at $DropBoxUrl
# *itself* accepts pipeline input.
'test' | 
  pwsh -NoProfile { 
    $input | & ([scriptblock]::Create($args[0])) 
  } -args (irm $DropBoxUrl)
mklement0
  • 382,024
  • 64
  • 607
  • 775