11

我想将 Keith Hill 的 Get-Clipboard 和 Set-Clipboard 的 C# 实现转换为纯 PowerShell 作为 .PSM1 文件。

有没有办法像他在使用剪贴板时在 Cmdlet 中那样在 PowerShell 中启动 STA 线程?

博客文章
代码

4

6 回答 6

16

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()
}
于 2009-10-15T15:54:21.270 回答
9

有关在 PowerShell Core 和 Windows PowerShell v2 - v4中提供剪贴板文本支持的跨版本、跨平台模块,请参阅底部部分。

尝试总结Windows PowerShell v5.1 / PowerShell Core v6.1.0状态和选项:

  • Windows PowerShell v5.0+:使用内置 Get-ClipboardSet-Clipboardcmdlet。

  • Windows PowerShell v4.0- (v1 - v4.0):没有用于与剪贴板交互的内置 cmdlet,但有一些解决方法

    • 使用PowerShell 社区扩展(PSCX; http://pscx.codeplex.com/ ),它附带了几个与剪贴板相关的 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种格式:

        • 系统当前的OEM 代码页(例如,IBM 437)
        • UTF-16 LE(“Unicode”)
        • 不幸的是,clip.exe总是将 BOM 视为数据,因此需要使用无 BOM编码
        • 请注意,上述编码仅与正确检测输入有关;一旦在剪贴板上,输入字符串就可以在以下所有编码中使用:UTF-16 LE、“ANSI”和 OEM。
    • 使用直接使用 .NET 类的基于 PowerShell 的解决方案

      • 请注意,剪贴板访问只能从 STA(单线程单元)模式下的线程进行 - 而不是 MTA(多线程单元):

        • v3:默认为STApowershell.exe (通过-mta开关调用可进入MTA模式)。
        • v2 和 v1:MTA 是默认的powershell.exe通过-sta开关调用可以进入STA模式。
        • 尔格:强大的功能应该能够在任一模式下从会话访问剪贴板。
  • PowerShell Core(多平台),从 v6.1.0 开始没有用于与剪贴板交互的内置 cmdlet,即使在Windows上运行也是如此。

    • 解决方法是使用特定于平台的实用程序或 API - 见下文。

我的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+ 上运行

    • 内置 cmdlet ( Get-Clipboard/ Set-Clipboard) 在幕后调用。
      请注意,自 v3 以来,STA 模式(COM 线程模型)是默认模式,但您可以使用命令行选项选择 MTA(多线程模式)-MTA
  • 在所有其他情况下(Windows PowerShell v4 和/或 MTA 模式,所有受支持平台上的 PowerShell Core ):

    • 视窗:
      • 使用调用 Windows API 的基于 AP/Invoke 的解决方案,通过使用Add-Type.
    • 类 Unix 平台:在后台调用本机实用程序:
      • macOS:pbcopypbpaste
      • Linux:,xclip如果可用并已安装
        例如,在 Ubuntu 上,使用sudo apt-get xclip安装。
  • Set-ClipboardText可以直接或从管道接受任何类型的对象作为输入(然后以与在控制台中呈现相同的方式将其转换为文本)。

  • 调用 with-Verbose查看在后台使用什么技术来访问剪贴板。


[1] 此答案的早期版本错误地声称clip.exe
- 复制到剪贴板时始终附加换行符(它不会) - 正确处理重定向到标准输入的文件
中的 UTF-16 LE BOM与输入通过管道传输时(也总是将 BOM 复制到剪贴板)。 <|clip.exe

于 2013-03-22T22:54:11.563 回答
4

我刚刚写了如何做到这一点:

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

-Oisin

于 2009-10-14T15:54:17.667 回答
1

你应该先检查你的主机。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 线程。

于 2009-10-14T16:35:10.877 回答
1

查看 PowerShell Cookbook 中 Lee Holme 的食谱:Set-Clipboard。您可以将 at 用作 Set-Clipboard.ps1,或者只是将代码放入 PowerShell 函数中(这是我的 PowerShell 配置文件中的一个示例)。

该脚本将允许您将完整的管道输出获取到剪贴板,例如:

dir | Set-Clipboard

我最初是从这个答案中了解到 Lee Holme 的解决方案的。

于 2013-01-26T19:11:43.163 回答
0

在 PowerShell 5 中,我们现在拥有Get-ClipboardSet-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)
于 2019-11-25T21:05:01.587 回答