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

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

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

博客文章
代码

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-ClipboardSet-Clipboard cmdlet。

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

    • 使用PowerShell社区扩展 (PSCX; http://pscx.codeplex.com/ ),它附带了几个与剪贴板相关的cmdlet,它们不仅仅处理文本。
    • 管道到标准命令行实用程序clip.exe (W2K3 +服务器端,Vista +客户端)[1]:

      • 注意:除了下面讨论的编码问题, ... | clip.exe ... | clip.exe总是在输入中附加一个尾随换行符 ; 避免这种情况的唯一方法是使用临时文件,其内容通过cmd< input redirection提供 - 请参阅下面的Set-ClipboardText函数。

      • 如果仅需要ASCII字符(7位)支持:默认情况下有效。

      • 如果只需要OEM编码(8位)支持 (例如,美国的IBM437),请首先运行以下命令:

        • $OutputEncoding = [System.Text.Encoding]::GetEncoding([System.Globalization.CultureInfo]::CurrentCulture.TextInfo.OEMCodePage)
      • 如果需要完整的Unicode支持,则必须使用不带BOMUTF-16 LE编码 ; 先运行以下命令:

        • $OutputEncoding = New-Object System.Text.UnicodeEncoding $false, $false # UTF-16 encoding *without BOM*
        • 用于测试的示例(PS控制台将显示亚洲字符。为“??”,但仍然正确处理它们 - 例如,在记事本中validation剪贴板内容):

          • "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中的错误 - 请参阅https: //github.com/PowerShell/PowerShell/issues/5763

        • 在非全局上下文中,使用(New-Object ...).psobject.BaseObject来解决bug,或者 - 在PSv5 +中 - 使用[...]:new()代替。
      • 注意: clip.exe显然理解2种格式:

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

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

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

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

我的ClipboardText模块提供了“polyfill”函数Get-ClipboardTextSet-ClipboardText用于从剪贴板获取和设置文本 ; 它们适用于Windows PowerShell v2 +以及PowerShell Core (有限制,见下文)。

在最简单的情况下(安装了包管理模块的PSv5 +或v3 / v4),您可以从提升/ sudo会话从PowerShell库安装它,如下所示

 Install-Module ClipboardText 

有关更多信息,包括先决条件和手动安装说明,请参阅存储库 。

  • 注意:严格来说,这些函数不是polyfill ,因为它们的名称与内置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 )在后台调用。
      请注意,STA模式(COM线程模型)是自v3以来的默认模式,但您可以使用命令行选项-MTA选择进入MTA(multithreading模式)。
  • 在所有其他情况下(Windows PowerShell v4-和/或MTA模式,所有支持的平台上的PowerShell Core ):

    • 在幕后调用本机实用程序:
      • Windows:用于设置文本的clip.exe和用于获取文本的WSH / JScript解决方案。
      • macOS: pbcopypbpaste
      • Linux: xclip如果可用并已安装 ;
        例如,在Ubuntu上,使用sudo apt-get xclip进行安装。
  • Set-ClipboardText可以接受任何类型的对象作为输入 (然后直接或从管道接收转换为文本的方式与它们在控制台中呈现的方式相同)。

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


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

我刚刚在博客上写了如何做到这一点:

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

-Oisin

你应该先检查你的主人。 ISE已经运行了STA,所以不需要再启动另一个线程或shell(这是我的todo列表中的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的高级function也可以让人们在脚本中使用自己的.NET线程。

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

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

 dir | Set-Clipboard 

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