Powershell's correspondend of con of command prompt?

匿名 (未验证) 提交于 2019-12-03 01:38:01

问题:

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

dir | tee con | clip 

The above doesn't work since con is not recognized as console in file system in PowerShell.

Also there may be the following scenario,

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

回答1:

You're going to want to collect your pipeline data and send it to the clipboard separately as @Mathias R. Jessen has suggested. The reason for this is that Clip is actually an external application and not something built into PowerShell that consumes information piped to it without any 'output' aside from the fact that it copies the information onto the clipboard.

dir | tee -var data $data | clip 

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

Alternately you could use Write-Host within a ForEach loop to write things to the screen, and still be able to pass them on the pipeline to clip, but the formatting of it may be undesirable, and most people suggest avoiding the use of write-host whenever possible. If you wanted to do it that way you could use something like:

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


回答2:

I think TheMadTechnician had the right idea for what you want to do. Write-Host as you pointed out, is not the same thing as letting the host display the object. The cmdlet you're looking for is Out-Host. So modifying TMT's suggestion:

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

The drawback to this is that it will print the headers for every object, instead of combining them, but I believe this is unavoidable because the only way the host is able to do that without stopping the pipeline is to be at the end of it.

Here it is as a function you can call on your own:

# 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 


回答3:

For such cases I prefer to use my own Invoke-Pipeline cmdlet:

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 to pass single input to multiple commands simultaneously like this:

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 #> 

With your example scenario 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 monitor output in multiple points.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!