我想将 Keith Hill 的 Get-Clipboard 和 Set-Clipboard 的 C# 实现转换为纯 PowerShell 作为 .PSM1 文件。
有没有办法像他在使用剪贴板时在 Cmdlet 中那样在 PowerShell 中启动 STA 线程?
我想将 Keith Hill 的 Get-Clipboard 和 Set-Clipboard 的 C# 实现转换为纯 PowerShell 作为 .PSM1 文件。
有没有办法像他在使用剪贴板时在 Cmdlet 中那样在 PowerShell 中启动 STA 线程?
TextBox 不需要 -STA 开关。
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()
}
有关在 PowerShell Core 和 Windows PowerShell v2 - v4中提供剪贴板文本支持的跨版本、跨平台模块,请参阅底部部分。
尝试总结Windows PowerShell v5.1 / PowerShell Core v6.1.0的状态和选项:
Windows PowerShell v5.0+:使用内置 Get-Clipboard
和Set-Clipboard
cmdlet。
Windows PowerShell v4.0- (v1 - v4.0):没有用于与剪贴板交互的内置 cmdlet,但有一些解决方法:
通过管道连接到标准命令行实用程序clip.exe
(W2K3+ 服务器端、Vista+ 客户端)[1]:
注意:除了下面讨论的编码问题外,... | clip.exe
总是在输入后面附加一个换行符;避免这种情况的唯一方法是使用临时文件,其内容是通过cmd的<
输入重定向提供的 - 请参见Set-ClipboardText
下面的函数。
如果只需要 ASCII 字符(7 位)支持:默认工作。
如果只需要OEM 编码(8 位)支持(例如,美国的 IBM437),请先运行以下命令:
$OutputEncoding = [System.Text.Encoding]::GetEncoding([System.Globalization.CultureInfo]::CurrentCulture.TextInfo.OEMCodePage)
如果需要完整的 Unicode 支持,则必须使用没有 BOM的UTF-16 LE 编码;首先运行以下命令:
$OutputEncoding = New-Object System.Text.UnicodeEncoding $false, $false # UTF-16 encoding *without BOM*
测试示例(PS 控制台会将亚洲字符显示为“??”,但仍能正确处理它们 - 例如,验证记事本中的剪贴板内容):
"I enjoyed Thomas Hübl's talk about 中文" | clip # should appear as is on the clipboard
注意:由于Windows PowerShell v5.1 / PowerShell Core v6.0.0-rc.2的错误,在全局$OutputEncoding
范围内按上述方式分配可以正常工作,但在其他情况下则不行,例如在function中 - 请参阅https:// github.com/PowerShell/PowerShell/issues/5763
(New-Object ...).psobject.BaseObject
来解决错误,或者 - 在 PSv5+ 中 -[...]:new()
改为使用。注意:clip.exe
显然理解2种格式:
clip.exe
总是将 BOM 视为数据,因此需要使用无 BOM编码。使用直接使用 .NET 类的基于 PowerShell 的解决方案:
请注意,剪贴板访问只能从 STA(单线程单元)模式下的线程进行 - 而不是 MTA(多线程单元):
powershell.exe
(通过-mta
开关调用可进入MTA模式)。powershell.exe
通过-sta
开关调用可以进入STA模式。PowerShell Core(多平台),从 v6.1.0 开始,没有用于与剪贴板交互的内置 cmdlet,即使在Windows上运行也是如此。
我的ClipboardText
模块提供
“polyfill”功能Get-ClipboardText
以及从剪贴板Set-ClipboardText
获取和设置文本;它们适用于Windows PowerShell v2+以及PowerShell Core(有限制,见下文)。
在最简单的情况下(安装了包管理模块的 PSv5+ 或 v3/v4),您可以通过提升的 /会话从 PowerShell 库安装它,如下所示sudo
:
Install-Module ClipboardText
有关更多信息,包括先决条件和手动安装说明,请参阅repo。
注意:严格来说,这些函数不是polyfills,因为它们的名称与内置 cmdlet 不同。但是,选择名称后缀Text是为了明确表明这些函数仅处理文本。
该代码非常感谢来自各个站点的信息,尤其是 @hoge 的回答 ( https://stackoverflow.com/a/1573295/45375 ) 和http://techibee.com/powershell/powershell-script-to-copy-powershell-命令输出到剪贴板/1316
在 STA 模式下在Windows PowerShell v5+ 上运行:
Get-Clipboard
/ Set-Clipboard
) 在幕后调用。-MTA
。在所有其他情况下(Windows PowerShell v4 和/或 MTA 模式,所有受支持平台上的 PowerShell Core ):
Add-Type
.pbcopy
和pbpaste
xclip
如果可用并已安装;sudo apt-get xclip
安装。Set-ClipboardText
可以直接或从管道接受任何类型的对象作为输入(然后以与在控制台中呈现相同的方式将其转换为文本)。
调用 with-Verbose
查看在后台使用什么技术来访问剪贴板。
[1] 此答案的早期版本错误地声称clip.exe
:
- 复制到剪贴板时始终附加换行符(它不会) - 正确处理重定向到标准输入的文件
中的 UTF-16 LE BOM与输入通过管道传输时(也总是将 BOM 复制到剪贴板)。
<
|
clip.exe
我刚刚写了如何做到这一点:
http://www.nivot.org/2009/10/14/PowerShell20GettingAndSettingTextToAndFromTheClipboard.aspx
-Oisin
你应该先检查你的主机。ISE 已经运行 STA,因此无需启动另一个线程或外壳(这是我的 PSCX 待办事项列表中的一项优化)。对于 MTA 的控制台提示符,我将使用 Oisin 显示的二进制代码或使用一个简单的小 C# 应用程序,例如:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class OutClipboard {
[STAThread]
static void Main() {
Clipboard.SetText(Console.In.ReadToEnd());
}
}
为了获取剪贴板内容,Vista 和更高版本有 clip.exe。
我认为即使是 2.0 的高级功能也不能让人们在脚本中使用自己的 .NET 线程。
查看 PowerShell Cookbook 中 Lee Holme 的食谱:Set-Clipboard。您可以将 at 用作 Set-Clipboard.ps1,或者只是将代码放入 PowerShell 函数中(这是我的 PowerShell 配置文件中的一个示例)。
该脚本将允许您将完整的管道输出获取到剪贴板,例如:
dir | Set-Clipboard
我最初是从这个答案中了解到 Lee Holme 的解决方案的。
在 PowerShell 5 中,我们现在拥有Get-Clipboard
和Set-Clipboard
.
在只有 PowerShell 4 的 Windows Server 2012 R2 上,我能够使用 .NET 来操作剪贴板。
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$copied = [System.Windows.Forms.Clipboard]::GetText()
$to_paste = 'Hello World'
[System.Windows.Forms.Clipboard]::SetText($to_paste)