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

发布于 2024-08-07 13:30:01 字数 390 浏览 9 评论 0原文

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

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

博客文章
代码

I'd like to convert Keith Hill's C# implementation of Get-Clipboard and Set-Clipboard into pure PowerShell as a .PSM1 file.

Is there a way to spin up an STA thread in PowerShell as he does in his Cmdlet when working with the clipboard?

The Blog Post
The Code

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

墨洒年华 2024-08-14 13:30:01

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()
}

TextBox doesn't require -STA switch.

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()
}
挖鼻大婶 2024-08-14 13:30:01

请参阅底部部分,了解提供剪贴板的跨版本、跨平台模块文本 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 总是在输入中附加一个尾随换行符;避免这种情况的唯一方法是使用临时文件,其内容通过 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 编码 *不带 BOM*
        • 测试示例(PS 控制台将亚洲字符显示为“??”,但仍正确处理它们 - 例如,在记事本中验证剪贴板内容):< /p>

          • “我很喜欢 Thomas Hübl 的中文演讲”|剪辑 # 应按原样显示在剪贴板上
      • 注意:如上所述分配给 $OutputEncoding全局范围内工作正常,但在其他情况下则不然,例如在函数中>,由于自 Windows PowerShell v5.1 / PowerShell Core v6.0.0-rc.2 起的一个错误 - 请参阅 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:默认为 STA(可以通过使用 -mta 开关调用 powershell.exe 来进入 MTA 模式)。
        • v2 和 v1:MTA 是默认值;可以通过使用 -sta 开关调用 powershell.exe 来进入 STA 模式。
        • 因此:强大的函数应该能够在任一模式下从会话访问剪贴板。
  • 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-command-output-to-clipboard/1316

  • 在 Windows PowerShell v5+ 上以 STA 模式运行:

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

    • Windows:
      • 使用基于 AP/Invoke 的解决方案,通过使用 Add-Type 编译的临时 C# 代码来调用 Windows API。
    • 类 Unix 平台:本机实用程序在幕后调用:
      • macOS:pbcopypbpaste
      • Linux:xclip如果可用并已安装
        例如,在 Ubuntu 上,使用 sudo apt-get xclip 进行安装。
  • Set-ClipboardText 可以接受任何类型的对象作为输入(然后以相同的方式转换为文本)它们会在控制台中渲染),可以直接渲染,也可以通过管道渲染。

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

    使用



[1] 此答案的早期版本错误地声称 clip.exe
- 复制到剪贴板时始终附加换行符(事实并非如此)
- 正确处理通过 < 重定向到 stdin 的文件中的 UTF-16 LE BOM,与通过 | 传输输入时的情况相比 (clip .exe也总是将 BOM 复制到剪贴板)。

See the bottom section for a cross-edition, cross-platform module that offers clipboard text support in PowerShell Core and in Windows PowerShell v2 - v4.

An attempt to summarize the state of affairs and options as of Windows PowerShell v5.1 / PowerShell Core v6.1.0:

  • Windows PowerShell v5.0+: Use the built-in Get-Clipboard and Set-Clipboard cmdlets.

  • Windows PowerShell v4.0- (v1 - v4.0): has no built-in cmdlets for interacting with the clipboard, but there are workarounds:

    • Use PowerShell Community Extensions (PSCX; http://pscx.codeplex.com/), which come with several clipboard-related cmdlets that go beyond just handling text.
    • Pipe to the standard command-line utility clip.exe (W2K3+ server-side, Vista+ client-side)[1]:

      • Note: Aside from the encoding issues discussed below, ... | clip.exe invariably appends a trailing newline to the input; the only way to avoid that is to use a temporary file whose content is provided via cmd's < input redirection - see the Set-ClipboardText function below.

      • If only ASCII-character (7-bit) support is needed: works by default.

      • If only OEM-encoding (8-bit) support (e.g., IBM437 in the US) is needed, run the following first:

        • $OutputEncoding = [System.Text.Encoding]::GetEncoding([System.Globalization.CultureInfo]::CurrentCulture.TextInfo.OEMCodePage)
      • If full Unicode support is needed, a UTF-16 LE encoding without BOM must be used; run the following first:

        • $OutputEncoding = New-Object System.Text.UnicodeEncoding $false, $false # UTF-16 encoding *without BOM*
        • Example to test with (the PS console will display the Asian chars. as "??", but still handle them correctly - verify clipboard content in Notepad, for instance):

          • "I enjoyed Thomas Hübl's talk about 中文" | clip # should appear as is on the clipboard
      • Note: Assigning to $OutputEncoding as above works fine in the global scope, but not otherwise, such as in a function, due to a bug as of Windows PowerShell v5.1 / PowerShell Core v6.0.0-rc.2 - see https://github.com/PowerShell/PowerShell/issues/5763

        • In a non-global context, use (New-Object ...).psobject.BaseObject to work around the bug, or - in PSv5+ - use [...]:new() instead.
      • Note: clip.exe apparently understands 2 formats:

        • the system's current OEM codepage (e.g., IBM 437)
        • UTF-16 LE ("Unicode")
        • Unfortunately, clip.exe always treats a BOM as data, hence the need to use a BOM-less encoding.
        • Note that the above encodings matter only with respect to correctly detecting input; once on the clipboard, the input string is available in all of the following encodings: UTF-16 LE, "ANSI", and OEM.
    • Use a PowerShell-based solution with direct use of .NET classes:

      • Note that clipboard access can only occur from a thread in STA (single-threaded apartment) mode - as opposed to MTA (multi-threaded apartment):

        • v3: STA is the default (MTA mode can be entered by invoking powershell.exe with the -mta switch).
        • v2 and v1: MTA is the default; STA mode can be entered by invoking powershell.exe with the -sta switch.
        • Ergo: Robust functions should be able to access the clipboard from sessions in either mode.
  • PowerShell Core (multi-platform), as of v6.1.0, has no built-in cmdlets for interacting with the clipboard, not even when run on Windows.

    • The workaround is to use platform-specific utilities or APIs - see below.

My ClipboardText module provides
"polyfill" functions Get-ClipboardText and Set-ClipboardText for getting and setting text from the clipboard; they work on Windows PowerShell v2+ as well as on PowerShell Core (with limitations, see below).

In the simplest case (PSv5+ or v3/v4 with the package-management modules installed), you can install it from the PowerShell Gallery from an elevated / sudo session as follows:

Install-Module ClipboardText

For more information, including prerequisites and manual-installation instructions, see the repo.

  • Note: Strictly speaking, the functions aren't polyfills, given that their names differ from the built-in cmdlets. However, the name suffix Text was chosen so as to make it explicit that these functions handle text only.

  • The code gratefully builds on information from various sites, notably @hoge's answer (https://stackoverflow.com/a/1573295/45375) and http://techibee.com/powershell/powershell-script-to-copy-powershell-command-output-to-clipboard/1316

  • Running on Windows PowerShell v5+ in STA mode:

    • The built-in cmdlets (Get-Clipboard / Set-Clipboard) are called behind the scenes.
      Note that STA mode (a COM threading model) is the default since v3, but you can opt into MTA (multi-threaded mode) with command-line option -MTA.
  • In all other cases (Windows PowerShell v4- and/or in MTA mode, PowerShell Core on all supported platforms):

    • Windows:
      • A P/Invoke-based solution that calls the Windows API is used, via ad-hoc C# code compiled with Add-Type.
    • Unix-like platforms: Native utilities are called behind the scenes:
      • macOS: pbcopy and pbpaste
      • Linux: xclip, if available and installed;
        for instance, on Ubuntu, use sudo apt-get xclip to install.
  • Set-ClipboardText can accept any type of object(s) as input (which is/are then converted to text the same way they would render in the console), either directly, or from the pipeline.

  • Invoke with -Verbose to see what technique is used behind the scenes to access the clipboard.



[1] An earlier version of this answer incorrectly claimed that clip.exe:
- always appends a line break when copying to the clipboard (it does NOT)
- correctly handles UTF-16 LE BOMs in files redirected to stdin via < vs. when input is piped via | (clip.exe always copies the BOM to the clipboard, too).

半仙 2024-08-14 13:30:01

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

You should check your host first. ISE already runs STA so there is no need to spin up another thread or shell out (which is an optimization that's on my todo list for PSCX). For the console prompt, which is MTA, then I would shell out to binary code either as Oisin shows or use a simple little C# app like:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class OutClipboard {
  [STAThread]
  static void Main() {
    Clipboard.SetText(Console.In.ReadToEnd());
  }
}

And for getting the clipboard contents, Vista and later have clip.exe.

I don't think that even 2.0's advanced functions is ready to let folks party with their own .NET threads in a script.

尬尬 2024-08-14 13:30:01

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

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

dir | Set-Clipboard

我最初是从这个答案。

Take a look at Lee Holme's recipe from the PowerShell Cookbook: Set-Clipboard. You can use at as Set-Clipboard.ps1, or just drop the code inside a PowerShell function (here's an example from my PowerShell profile).

The script will allow you to get the full piped output to the clipboard, e.g.:

dir | Set-Clipboard

I originally learned of Lee Holme's solution from this answer.

洋洋洒洒 2024-08-14 13:30:01

在 PowerShell 5 中,我们现在有 Get-ClipboardSet-Clipboard

在 Windows Server 2012 R2 上,我们只有 PowerShell 4,我能够使用 .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)

In PowerShell 5, we now have Get-Clipboard and Set-Clipboard.

On Windows Server 2012 R2, where we only have PowerShell 4, I was able to use .NET to manipulate the clipboard.

[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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文