I'd like to convert Keith Hill's C# implementation of Get-Clipboard and Set-Clipboard into pure PowerShell as a .PSM1 file.
Is there a way to spin up an STA thread in PowerShell as he does in his Cmdlet when working with the clipboard?
The Blog Post
The Code
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:
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
(New-Object ...).psobject.BaseObject
to work around the bug, or - in PSv5+ - use [...]:new()
instead.Note: clip.exe
apparently understands 2 formats:
clip.exe
always treats a BOM as data, hence the need to use a BOM-less encoding.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):
powershell.exe
with the -mta
switch).powershell.exe
with the -sta
switch.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.
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:
Get-Clipboard
/ Set-Clipboard
) are called behind the scenes.-MTA
.In all other cases (Windows PowerShell v4- and/or in MTA mode, PowerShell Core on all supported platforms):
Add-Type
.pbcopy
and pbpaste
xclip
, if available and installed;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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With