1

I have a subprocess that I want to call from powershell that might be interactive or I might pipe data straight into it. For example:

# This is interactive:
& c:\python27\python.exe

# This takes redirected input:
echo hi | & c:\python27\python.exe -c "print repr(raw_input())"

I want to create a function that can be used to wrap a call to such a process. I can do this:

function python() {
    & c:\python27\python.exe @args
}

# This starts an interactive prompt:
python

# The piped data disappears and the process still reads from the console:
echo hi | python -c "print repr(raw_input())"

Or I can do this:

function python() {
    $input | & c:\python27\python.exe @args
}

# This doesn't accept interactive input:
python

# The piped data is passed through to the sub-process as intended:
echo hi | python -c "print repr(raw_input())"

I cannot figure out how to write a function that handles both cases. If it's invoked without a pipeline, I want it start a subprocess that reads from stdin, and if it's invoked with a pipeline input, I want it to feed that into the subprocess's stdin. Can I do this?

2

You can check value of $MyInvocation.ExpectingInput expression to find out did your function expect any pipeline input or it is the first element of pipeline.

function python {
    if($MyInvocation.ExpectingInput){
        $input | & c:\python27\python.exe @args
    }else{
        & c:\python27\python.exe @args
    }
}
1

Define parameter in the function, that will hold your data. Then check if parameter is supplied and act accordingly. You might have to do some tweaking due to the way how PowerShell passes data to external programs, but the basic idea stands.

Barebone example:

Usage:

'foo', '', 'bar' | Invoke-Python

Here I'm passing an array to the Invoke-Python function.

Result:

  • 'foo' will be piped to the python
  • Then, function will encounter empty parameter and invoke interactive python
  • After you exit the interactive python, the function will pipe 'bar' to the python

Invoke-Python function:

function Invoke-Python
{
    [CmdletBinding()]
    Param
    (
        # This parameter will catch your input data
        [Parameter(ValueFromPipeline = $true)]
        [string]$InputObject
    )

    # This block runs when pipeline is initialized.
    # It doesn't have access to the parameters,
    # they are not yet parsed at this time.
    Begin
    {
        # Set path to the python
        $PythonPath = 'c:\python27\python.exe'
    }

    # This block runs for each pipeline item
    Process
    {
        # Check, is there anything passed in the InputObject parameter
        if($InputObject)
        {
            Write-Host 'We have some data, let''s pipe it into the python'
            $InputObject | & $PythonPath @('-c', 'print repr(raw_input())')
        }
        else
        {
            Write-Host 'No data, let''s just launch interactive python'
            & $PythonPath
        }
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.