Command line Powershell correspondent will prompt?

For example, I want to show the output on the screen and copy it to the clipboard.

dir | tee con | clip

      

The above does not work as it is con

not recognized as a console on the file system in PowerShell.

There could also be the following scenario,

Get-LongLongOutput | 
tee con | # Monitor the intermediate output
Process-LongLongInput | 
Process-LongLongInput2 | 
..... 

      

+3


source to share


3 answers


You will want to collect your pipeline data and send it to the clipboard separately, as @Mathias R. Jessen suggested. The reason for this is that it Clip

is actually an external application, not embedded in PowerShell, that consumes information passed to it without any "exits" other than copying information to the clipboard.

dir | tee -var data
$data | clip

      

This (as suggested by @Mathias R. Jessen) will display your content as well as copy it to the clipboard.



Alternatively, you can use Write-Host

ForEach in a loop to write things to the screen and still be able to pipe them to Clip

, but formatting it might not be desirable and most people suggest avoiding using Write-Host

it whenever possible. If you want to do this, you can use something like:

dir | ForEach-Object{
    Write-Host $_
    $_} | Clip

      

+2


source


I think TheMadTechnician had the right idea for what you want to do. Write-Host

as you pointed out this is not the same as letting the host render the object. The cmdlet you are looking for is Out-Host

. Thus, the change in the TMT proposal:

Get-Process | ForEach-Object {
    $_ | Out-Host
    $_
} | clip

      

The downside to this is that it will print headers for each object rather than combining them, but I believe this is inevitable because the only way the host can do this without stopping the pipeline should be at the end of it.



Here it is like a function that you can call yourself:

# Don't use this terrible name
Function MyTeeFine {
[CmdletBinding()]
param(
    [Parameter(ValueFromPipeline=$true)]
    $object
)

    process {
        $object | Out-Host
        $object
    }
}

# In action:

Get-Process | MyTeeFine | clip
Get-Process | MyTeeFine | ForEach-Object { Start-Sleep -Seconds 1 } 
# ^ proof that the pipeline is still working object by object, 
# displaying to host before each delay

      

+2


source


In such cases, I prefer to use my own cmdlet Invoke-Pipeline

:

Add-Type -TypeDefinition @‘
using System;
using System.Management.Automation;
[Cmdlet(VerbsLifecycle.Invoke,"Pipeline")]
public sealed class InvokePipelineCmdlet:PSCmdlet,IDisposable {
    private static readonly Type StopUpstreamCommandsExceptionType=typeof(FlowControlException).Assembly.GetType("System.Management.Automation.StopUpstreamCommandsException");
    private ScriptBlock[] scriptBlocks;
    private PSObject inputObject;
    private int count;
    private SteppablePipeline[] steppablePipelines;
    public InvokePipelineCmdlet() { }
    [Parameter(Mandatory=true,ValueFromRemainingArguments=true)]
    public ScriptBlock[] Pipeline {
        set {
            scriptBlocks=value;
        }
    }
    [Parameter(ValueFromPipeline=true)]
    public PSObject InputObject {
        get {
            return null;
        }
        set {
            inputObject=value;
        }
    }
    protected override void BeginProcessing() {
        count=scriptBlocks.Length;
        steppablePipelines=new SteppablePipeline[count];
        for(int i=0;i<count;++i) {
            steppablePipelines[i]=scriptBlocks[i].GetSteppablePipeline(MyInvocation.CommandOrigin);
        }
        ProcessPipelineStep(PipelineStep.Begin);
    }
    protected override void ProcessRecord() {
        ProcessPipelineStep(MyInvocation.ExpectingInput?PipelineStep.ProcessInput:PipelineStep.Process);
    }
    protected override void EndProcessing() {
        ProcessPipelineStep(PipelineStep.End);
        Dispose();
    }
    public void Dispose() {
        if(steppablePipelines!=null) {
            foreach(SteppablePipeline steppablePipeline in steppablePipelines) {
                if(steppablePipeline!=null) {
                    steppablePipeline.Dispose();
                }
            }
            steppablePipelines=null;
        }
    }
    private void ProcessPipelineStep(PipelineStep step) {
        if(steppablePipelines!=null) {
            for(int i=0;i<steppablePipelines.Length;++i) {
                if(steppablePipelines[i]!=null) {
                    try {
                        switch(step) {
                            case PipelineStep.Begin:
                                steppablePipelines[i].Begin(this);
                                break;
                            case PipelineStep.Process:
                                steppablePipelines[i].Process();
                                break;
                            case PipelineStep.ProcessInput:
                                steppablePipelines[i].Process(inputObject);
                                break;
                            case PipelineStep.End:
                                steppablePipelines[i].End();
                                break;
                        }
                    } catch(FlowControlException fce) {
                        if(StopUpstreamCommandsExceptionType.IsInstanceOfType(fce)) {
                            steppablePipelines[i]=null;
                            if(--count==0) {
                                EndProcessing();
                                throw (FlowControlException)Activator.CreateInstance(StopUpstreamCommandsExceptionType,this);
                            }
                        } else {
                            throw;
                        }
                    }
                }
            }
        }
    }
    private enum PipelineStep {
        Begin,
        Process,
        ProcessInput,
        End
    }
}
’@ -PassThru|Select-Object -First 1 -ExpandProperty Assembly|Import-Module

      

It allows one input to be passed to multiple commands at the same time as follows:

dir|Invoke-Pipeline {clip} <# copy to clipboard #> `
                    {Out-File out.txt} <# save to file #> `
                    {Out-File outall.txt -Append} <# append to some other file #> `
                    {Out-Host} <# display on console #>

      

In your example script, you can do the following:

Get-LongLongOutput |
Invoke-Pipeline {Out-Host} {Process-LongLongInput} |
Process-LongLongInput2 |
.....

      

Or you can do something like this:

Get-LongLongOutput |
Invoke-Pipeline {Out-GridView} {Process-LongLongInput} |
Invoke-Pipeline {Out-GridView} {Process-LongLongInput2} |
.....

      

so you can control the output at multiple points.

+1


source







All Articles