Convert Keith Hill's PowerShell Get-Clipboard and Set-Clipboard to a PSM1 script

TextBox doesn't require -STA switch.

function Get-ClipBoard {
    Add-Type -AssemblyName System.Windows.Forms
    $tb = New-Object System.Windows.Forms.TextBox
    $tb.Multiline = $true
    $tb.Paste()
    $tb.Text
}


function Set-ClipBoard() {
    Param(
      [Parameter(ValueFromPipeline=$true)]
      [string] $text
    )
    Add-Type -AssemblyName System.Windows.Forms
    $tb = New-Object System.Windows.Forms.TextBox
    $tb.Multiline = $true
    $tb.Text = $text
    $tb.SelectAll()
    $tb.Copy()
}

See the bottom section for a cross-edition, cross-platform module that offers clipboard text support in PowerShell Core and in Windows PowerShell v2 - v4.

An attempt to summarize the state of affairs and options as of Windows PowerShell v5.1 / PowerShell Core v6.1.0:

  • Windows PowerShell v5.0+: Use the built-in Get-Clipboard and Set-Clipboard cmdlets.

  • Windows PowerShell v4.0- (v1 - v4.0): has no built-in cmdlets for interacting with the clipboard, but there are workarounds:

    • Use PowerShell Community Extensions (PSCX; http://pscx.codeplex.com/), which come with several clipboard-related cmdlets that go beyond just handling text.
    • Pipe to the standard command-line utility clip.exe (W2K3+ server-side, Vista+ client-side)[1]:

      • Note: Aside from the encoding issues discussed below, ... | clip.exe invariably appends a trailing newline to the input; the only way to avoid that is to use a temporary file whose content is provided via cmd's < input redirection - see the Set-ClipboardText function below.

      • If only ASCII-character (7-bit) support is needed: works by default.

      • If only OEM-encoding (8-bit) support (e.g., IBM437 in the US) is needed, run the following first:

        • $OutputEncoding = [System.Text.Encoding]::GetEncoding([System.Globalization.CultureInfo]::CurrentCulture.TextInfo.OEMCodePage)
      • If full Unicode support is needed, a UTF-16 LE encoding without BOM must be used; run the following first:

        • $OutputEncoding = New-Object System.Text.UnicodeEncoding $false, $false # UTF-16 encoding *without BOM*
        • Example to test with (the PS console will display the Asian chars. as "??", but still handle them correctly - verify clipboard content in Notepad, for instance):

          • "I enjoyed Thomas Hübl's talk about 中文" | clip # should appear as is on the clipboard
      • Note: Assigning to $OutputEncoding as above works fine in the global scope, but not otherwise, such as in a function, due to a bug as of Windows PowerShell v5.1 / PowerShell Core v6.0.0-rc.2 - see https://github.com/PowerShell/PowerShell/issues/5763

        • In a non-global context, use (New-Object ...).psobject.BaseObject to work around the bug, or - in PSv5+ - use [...]:new() instead.
      • Note: clip.exe apparently understands 2 formats:

        • the system's current OEM codepage (e.g., IBM 437)
        • UTF-16 LE ("Unicode")
        • Unfortunately, clip.exe always treats a BOM as data, hence the need to use a BOM-less encoding.
        • Note that the above encodings matter only with respect to correctly detecting input; once on the clipboard, the input string is available in all of the following encodings: UTF-16 LE, "ANSI", and OEM.
    • Use a PowerShell-based solution with direct use of .NET classes:

      • Note that clipboard access can only occur from a thread in STA (single-threaded apartment) mode - as opposed to MTA (multi-threaded apartment):

        • v3: STA is the default (MTA mode can be entered by invoking powershell.exe with the -mta switch).
        • v2 and v1: MTA is the default; STA mode can be entered by invoking powershell.exe with the -sta switch.
        • Ergo: Robust functions should be able to access the clipboard from sessions in either mode.
  • PowerShell Core (multi-platform), as of v6.1.0, has no built-in cmdlets for interacting with the clipboard, not even when run on Windows.

    • The workaround is to use platform-specific utilities or APIs - see below.

My ClipboardText module provides "polyfill" functions Get-ClipboardText and Set-ClipboardText for getting and setting text from the clipboard; they work on Windows PowerShell v2+ as well as on PowerShell Core (with limitations, see below).

In the simplest case (PSv5+ or v3/v4 with the package-management modules installed), you can install it from the PowerShell Gallery from an elevated / sudo session as follows:

Install-Module ClipboardText

For more information, including prerequisites and manual-installation instructions, see the repo.

  • Note: Strictly speaking, the functions aren't polyfills, given that their names differ from the built-in cmdlets. However, the name suffix Text was chosen so as to make it explicit that these functions handle text only.

  • The code gratefully builds on information from various sites, notably @hoge's answer (https://stackoverflow.com/a/1573295/45375) and http://techibee.com/powershell/powershell-script-to-copy-powershell-command-output-to-clipboard/1316

  • Running on Windows PowerShell v5+ in STA mode:

    • The built-in cmdlets (Get-Clipboard / Set-Clipboard) are called behind the scenes.
      Note that STA mode (a COM threading model) is the default since v3, but you can opt into MTA (multi-threaded mode) with command-line option -MTA.
  • In all other cases (Windows PowerShell v4- and/or in MTA mode, PowerShell Core on all supported platforms):

    • Windows:
      • A P/Invoke-based solution that calls the Windows API is used, via ad-hoc C# code compiled with Add-Type.
    • Unix-like platforms: Native utilities are called behind the scenes:
      • macOS: pbcopy and pbpaste
      • Linux: xclip, if available and installed;
        for instance, on Ubuntu, use sudo apt-get xclip to install.
  • Set-ClipboardText can accept any type of object(s) as input (which is/are then converted to text the same way they would render in the console), either directly, or from the pipeline.

  • Invoke with -Verbose to see what technique is used behind the scenes to access the clipboard.


[1] An earlier version of this answer incorrectly claimed that clip.exe:
- always appends a line break when copying to the clipboard (it does NOT)
- correctly handles UTF-16 LE BOMs in files redirected to stdin via < vs. when input is piped via | (clip.exe always copies the BOM to the clipboard, too).


I just blogged how to do this:

http://www.nivot.org/2009/10/14/PowerShell20GettingAndSettingTextToAndFromTheClipboard.aspx

-Oisin