Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

PowerShell Friday Fun: Capture the Command

Posted on October 30, 2015October 30, 2015

This week's Friday Fun actually has a purpose, at least for me. But I always hope you'll pick up a tip or two that you can use in your own PowerShell work.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

Because I write a lot about PowerShell, I am constantly copying pasting between my PowerShell session and usually Microsoft Word. Although the same is true when I am writing help examples for my functions. I can save command output to the clipboard with this trick:

Get-service | Group Status | clip

But I never know if the command was successful until I paste and then I need to copy the command again. Over the years I've come up with a number of tools to make this process easier but now I think I finally have it.

My new command is called Out-Copy. It is designed to accept any PowerShell command. The function will essentially pass the results back to the pipeline, so it is like Tee-Object in that respect. It also sends a copy of the output to the clipboard. But wait there's more! The clipboard output will include the prompt and the command you ran.

At a PowerShell prompt I can run something like this:

Using Out-CopyUsing Out-Copy (Image Credit: Jeff Hicks)

And I can then paste into another application

Pasted resultsPasted results (Image Credit: Jeff Hicks)

I also included a parameter to only copy the command to the clipboard. This command runs as expected:

Copying command onlyCopying command only (Image Credit: Jeff Hicks)

With this result:

Command only resultCommand only result (Image Credit: Jeff Hicks)

This version of my function will only copy what is sent to the success pipeline. It will not capture anything from the other streams such as Verbose, Warning or Error. Normally I do screen shots of that anyway. But this might be something I'll look into later.

Here's the complete function which includes an alias.

#requires -version 4.0

Function Out-Copy {

<#
.Synopsis
Send command output to the pipeline and Windows clipboard.
.Description
This command is intended for writers and those who need to document with PowerShell. You can pipe any command to this function and you will get the regular output in your PowerShell session. But a copy of the output will be copied to the Windows clipboard. Additionally, the copy will include your prompt and the command that you executed, without the Out-Copy portion.

NOTE: You can only capture what is written to the Success pipeline. This command will not copy any other streams such as Verbose or Error.
.Parameter CommandOnly
Only copy the executed command, without references to Out-Copy, to the Windows clipboard.
.Parameter Width
Specifies the number of characters in each line of output. Any additional characters are truncated, not wrapped.
.Example
PS C:\> Get-Process | Sort WS -Descending | Select -first 5 | out-copy

This will execute your expression and write the output to the pipeline. In addition this text will be copied to the Windows clipboard:

PS C:\> Get-Process | Sort WS -Descending | Select -first 5

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
1242 133 1047776 1002596 1987 4,499.78 1416 waterfox
1182 101 438800 409020 1285 854.53 6528 powershell_ise
321 22 245568 202236 362 730.05 2484 ZeroConfigService
1314 177 229772 187324 792 ...70.95 6500 SugarSync
651 37 199160 162216 343 597.16 1052 svchost

.Example
PS C:\scripts> dir *.ps1 | out-file c:\work\ps.txt

Even if your command doesn't write anything to the pipeline, Out-Copy will still capture your prompt and PowerShell expression.
.Example
PS C:\> gcim win32_logicaldisk -filter "drivetype = 3" | out-copy -commandonly

This will run the Get-CimInstance command and write results to the pipeline. But the only text that will be copied to the clipboard is:

gcim win32_logicaldisk -filter "drivetype = 3"

.Notes
Last Updated: 30 October 2015
Version : 1.0

Learn more about PowerShell:
Essential PowerShell Learning Resources
**************************************************************** * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED * * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK. IF * * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, * * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING. * **************************************************************** .Link Out-String .Inputs [object] .Outputs [object] #> [cmdletbinding()] Param( [Parameter(Mandatory,ValueFromPipeline)] [object]$InputObject, [ValidateNotNullorEmpty()] [int]$Width = 80, [switch]$CommandOnly ) Begin { Write-Verbose "Starting: $($MyInvocation.Mycommand)" Write-Verbose "Adding necessary .NET assembly" Add-Type -AssemblyName system.windows.forms #initialize an array to hold all incoming data $Data = @() } #begin Process { #add each input to the array $data += $InputObject } #process End { Write-Verbose "In the End block" #write data to the pipeline Write-Verbose "Here is the PowerShell output" $data Write-Verbose "Getting the currently running command" $Invoked = $MyInvocation.Line #parse out the Out-Copy command $cmd = $Invoked.substring(0,$invoked.LastIndexOf("|")) if ($CommandOnly) { Write-Verbose "Copying command expression" $Text = $cmd } else { #convert data to text Write-Verbose "Getting current prompt" $text = "$((Prompt | Out-String).Trim()) " $text += $cmd #insert a blank line $text += "`n" Write-Verbose "Converting data to text" #using a regular expression to try and clean up the output $text += ($data | Out-String -Width $Width) -replace "(?<=\S*)\s+`r`n$","`r`n" } Write-Verbose "Copy text to the clipboard" [System.Windows.Forms.Clipboard]::SetText( $text,[System.Windows.Forms.TextDataFormat]::Text) Write-Verbose "Ending: $($MyInvocation.Mycommand)" } #end } #define an alias Set-Alias -Name oc -Value Out-Copy

The only other parameter is Width. I have given this a default value of 80 which works best when pasting into a Word or text document. You can adjust this, typically up to the width of your PowerShell host. Anything beyond will be truncated.

I spent a few hours polishing this up, but it will save me time and frustration from here on out and maybe you will need to use it to. Plus it puts a smile on my face when I use it because I feel like I'm performing magic.

Enjoy!


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

5 thoughts on “PowerShell Friday Fun: Capture the Command”

  1. adam says:
    October 30, 2015 at 12:32 pm

    Out-Copy is a very handy function. Thanks!

    1. Jeffery Hicks says:
      October 30, 2015 at 12:38 pm

      Thanks for the feedback. How do you think you’ll use it?

  2. Alex B Chalmers says:
    October 30, 2015 at 12:45 pm

    Is there a reason you delay writing the data back to the pipeline to the end block, rather than writing it directly back to the pipeline in the process block?

    I know the intent of your code is to only run at the end of a pipeline, in which case you aren’t delaying it by much. That said, I could see a corner case for running Out-Copy in the middle of a pipeline. In that case, you are delaying any further processing of the objects until your command completes. Correcting that issue is a simple matter of adding a “Write-Output $InputObject” line in the process block and removing your “$Data” line from the end block.

    That use case would also prevent your simple trim for capturing the command line. I would end up getting the aliases and examine the line for the command or its aliases and trimming it out, but you could end up with issues with concurrency if multiple Out-Copy commands are run at the same time. I will try playing with it and see if I can come up with a workable solution.

    1. Jeffery Hicks says:
      October 30, 2015 at 12:53 pm

      I initially was passing output in the process block. But the result was a single formatted object. So that instead of getting a result like you would see with Get-Service I was getting this:

      Status Name DisplayName
      —— —- ———–
      Stopped AdobeFlashPlaye… Adobe Flash Player Update Service

      Status Name DisplayName
      —— —- ———–
      Stopped AeLookupSvc Application Experience

      Status Name DisplayName
      —— —- ———–
      Running BITS Background Intelligent Transfer Ser…

      But I’m open to revisiting this.

  3. Larry Weiss says:
    October 30, 2015 at 4:55 pm

    This works well with this clipboard archive utility by Boe Prox at
    https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Clipboard-c414ec78
    also written in PowerShell.

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d