将Keith Hill的PowerShell Get-Clipboard和Set-Clipboard转换为PSM1脚本

时间:2009-10-14 15:32:32

标签: c# powershell multithreading sta

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

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

The Blog Post
The Code

6 个答案:

答案 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 ,但有变通办法

    • 使用 PowerShell社区扩展(PSCX; 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种格式:

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

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

        • v3: STA是默认(可以通过powershell.exe开关调用-mta来输入MTA模式。
        • v2和v1: MTA是默认;可以通过powershell.exe开关调用-sta来输入STA模式。
        • Ergo:强大的功能应该能够在任一模式下从会话访问剪贴板。
  • PowerShell 核心 (多平台), v6.1.0 no < / em>用于与剪贴板交互的内置cmdlet ,即使在 Windows 上运行也不行。

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

我的https://github.com/PowerShell/PowerShell/issues/5763提供了 的&#34;填充工具&#34;函数Get-ClipboardTextSet-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 +

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

    • 视窗:
      • 通过使用Add-Type编译的临时C#代码,使用调用Windows API的基于P / Invoke的解决方案。
    • 类Unix平台:在幕后调用本机实用程序:
      • macOS:pbcopypbpaste
      • Linux:xclip ,如果可用且已安装;

        例如,在Ubuntu上,使用sudo apt-get xclip进行安装。
  • Set-ClipboardText可以接受任何类型的对象作为输入(然后将其转换为文本,就像它们一样在控制台中渲染,直接或从管道渲染。

  • 使用-Verbose调用,以查看幕后使用的技术来访问剪贴板。


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

答案 2 :(得分:4)

答案 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-ClipboardSet-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)