我想将Keith Hill的Get-Clipboard和Set-Clipboard的C#实现转换为纯PowerShell作为.PSM1文件。
有没有办法在PowerShell中启动STA线程,就像他在使用剪贴板时在Cmdlet中那样?
答案 0 :(得分:15)
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()
}
答案 1 :(得分:8)
请参阅底部部分,了解在PowerShell Core和Windows PowerShell v2-v4中提供剪贴板 text 支持的cross-edition, cross-platform module。
尝试总结 Windows PowerShell v5.1 / PowerShell 核心 v6.1.0 的事态和选项:
Windows PowerShell v5.0 + :使用 内置 { {3}}和Get-Clipboard
cmdlet。
Windows PowerShell v4.0 - (v1 - v4.0): 否< / em>用于与剪贴板交互的内置cmdlet ,但有变通办法:
Set-Clipboard
),它附带了几个与剪贴板相关的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支持,则必须使用 UTF-16 LE编码无BOM ;首先运行以下内容:
$OutputEncoding = New-Object System.Text.UnicodeEncoding $false, $false # UTF-16 encoding *without BOM*
测试的示例(PS控制台将显示亚洲字符。&#34; ??&#34;,但仍然正确处理它们 - 在记事本中验证剪贴板内容,例如):
"I enjoyed Thomas Hübl's talk about 中文" | clip # should appear as is on the clipboard
注意:如上所述分配给$OutputEncoding
在全局范围内可以正常工作,但在其他情况下则无效,例如在功能中,由于Windows PowerShell v5.1 / PowerShell Core v6.0.0-rc.2中的错误 - 请参阅http://pscx.codeplex.com/
(New-Object ...).psobject.BaseObject
来解决错误,或者 - 在PSv5 +中 - 使用[...]:new()
代替。注意:clip.exe
显然理解2种格式:
clip.exe
始终将BOM视为数据,因此需要使用BOM- less 编码。使用基于PowerShell的解决方案直接使用.NET类:
请注意,剪贴板访问只能从STA(单线程单元)模式中的线程进行 - 而不是MTA(多线程单元):
powershell.exe
开关调用-mta
来输入MTA模式。powershell.exe
开关调用-sta
来输入STA模式。PowerShell 核心 (多平台), v6.1.0 , no < / em>用于与剪贴板交互的内置cmdlet ,即使在 Windows 上运行也不行。
我的https://github.com/PowerShell/PowerShell/issues/5763提供了
的&#34;填充工具&#34;函数Get-ClipboardText
和Set-ClipboardText
用于从剪贴板获取和设置文本 ;他们使用 Windows PowerShell v2 + 以及 PowerShell Core (有限制,见下文)。
在最简单的情况下(安装了软件包管理模块的PSv5 +或v3 / v4),您可以从提升/ sudo
会话安装ClipboardText
module,如下所示 :
Install-Module ClipboardText
有关详细信息,包括先决条件和手动安装说明,请参阅from the PowerShell Gallery。
注意:严格来说,这些功能不是 polyfills ,因为它们的名称与内置cmdlet不同。但是,选择了名称后缀 Text ,以便明确表示这些函数仅处理文本。
代码非常感谢来自各个网站的信息,特别是@ hoge的答案(the repo)和https://stackoverflow.com/a/1573295/45375
在STA模式下运行 Windows PowerShell v5 + :
Get-Clipboard
/ Set-Clipboard
)在幕后调用。-MTA
选择进入MTA(多线程模式)。在所有其他情况下(Windows PowerShell v4-和/或MTA模式,所有支持的平台上的PowerShell Core ):
Add-Type
编译的临时C#代码,使用调用Windows API的基于P / Invoke的解决方案。pbcopy
和pbpaste
xclip
, ,如果可用且已安装; sudo apt-get xclip
进行安装。 Set-ClipboardText
可以接受任何类型的对象作为输入(然后将其转换为文本,就像它们一样在控制台中渲染,直接或从管道渲染。
使用-Verbose
调用,以查看幕后使用的技术来访问剪贴板。
[1]此答案的早期版本错误地声称clip.exe
:
- 复制到剪贴板时总是附加换行符(不是)
- 正确处理文件中的UTF-16 LE物料清单通过<
重定向到标准输入端,而输入通过|
管道输入(clip.exe
始终也将BOM复制到剪贴板。
功能
答案 2 :(得分:4)
我刚刚在博客上写了这个:
http://www.nivot.org/2009/10/14/PowerShell20GettingAndSettingTextToAndFromTheClipboard.aspx
-Oisin
答案 3 :(得分:1)
您应该先检查您的主机。 ISE已经运行了STA,所以不需要再启动另一个线程或shell(这是我在PSCX上的todo列表中的优化)。对于控制台提示符,即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线程。
答案 4 :(得分:1)
从PowerShell Cookbook中查看Lee Holme的食谱:Set-Clipboard。您可以使用at作为Set-Clipboard.ps1,或者只是将代码放在PowerShell函数中(here's an example来自我的PowerShell配置文件)。
该脚本允许您将完整的管道输出到剪贴板,例如:
dir | Set-Clipboard
我最初从this answer了解到Lee Holme的解决方案。
答案 5 :(得分:0)
在PowerShell 5中,我们现在有Get-Clipboard
和Set-Clipboard
。
在只有Server 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)