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?
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?
I just blogged how to do this:
http://www.nivot.org/2009/10/14/PowerShell20GettingAndSettingTextToAndFromTheClipboard.aspx
-Oisin
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
andSet-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 theSet-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" functionsGet-ClipboardText
andSet-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: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.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):
Add-Type
.pbcopy
andpbpaste
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).TextBox doesn't require -STA switch.
Take a look at Lee Holme's recipe from the PowerShell Cookbook: Set-Clipboard. You can use at as Set-Clipboard.ps1, or just drop the code inside a PowerShell function (here's an example from my PowerShell profile).
The script will allow you to get the full piped output to the clipboard, e.g.:
I originally learned of Lee Holme's solution from this answer.
You should check your host first. ISE already runs STA so there is no need to spin up another thread or shell out (which is an optimization that's on my todo list for PSCX). For the console prompt, which is MTA, then I would shell out to binary code either as Oisin shows or use a simple little C# app like:
And for getting the clipboard contents, Vista and later have clip.exe.
I don't think that even 2.0's advanced functions is ready to let folks party with their own .NET threads in a script.