Enumerating Windows clipboard history in PowerShell

Raymond Chen

Last time, we enumerated the contents of the Windows clipboard history from C++/WinRT and C#. Today we’ll do it from PowerShell.

Because, hey, why not.

$null = [Windows.ApplicationModel.DataTransfer.Clipboard, Windows.ApplicationModel.DataTransfer, ContentType=WindowsRuntime]
$op = [Windows.ApplicationModel.DataTransfer.Clipboard]::GetHistoryItemsAsync()

$result = Await ($op) `
    ([Windows.ApplicationModel.DataTransfer.ClipboardHistoryItemsResult])

$textops = $result.Items.Content.GetTextAsync()
for ($i = 0; $i -lt $textops.Count; $i++){ Await($textops[$i]) ([String]) }

It’s basically the same thing we’ve been doing, just written in PowerShell. Note that I’m not a PowerShell expert, so some of the things I’m doing may be suboptimal.

First, we load the Clipboard class into memory, specifying that it is a Windows Runtime class.

Next, we call Get­History­Items­Async and Await it to get the history items result.

We take the Items from the result, get their Content, and ask each Content for its text.

The text query is another asynchronous operation, so we iterate through the operations and Await each one, sending the results back into the pipeline.

I didn’t add the code to check ahead of time whether the content contained text. I just let the exception flow out of the Get­Text­Async call. Fixing this is left as an exercise.

10 comments

Discussion is closed. Login to edit/delete existing comments.

  • Mystery Man 0

    Doesn’t work. The first line of the script returns the following error.

    InvalidOperation: Unable to find type [Windows.ApplicationModel.DataTransfer.Clipboard,Windows.ApplicationModel.DataTransfer, ContentType=WindowsRuntime].

    From that point onward, it’s all failures.

    • Andrew Timson 0

      Windows PowerShell can find the type, PowerShell 7 can’t. (I still get issues later on because $result.Items.Content is null, though.)

      • Mystery Man 1

        Ironic. I remember a time when Microsoft had an undue focus on backward compatibility. Now its contemporary technologies aren’t compatible with each other. The “I” in “API” stands for “Interface” but whoever made Windows.ApplicationModel.DataTransfer.Clipboard didn’t get the memo.

        • Paulo Pinto 1

          The way UWP, WinUI. .NET Native, C++/CX migration has been managed has been a joke on us, see the amount of issues on Github, Developer Connection and missing features.

          PowerShell being another victim of this mess is yet another symptom.

          It is quite hard to stay commited to Windows desktop nowadays, other than classical Win32 and .NET APIs, everything else is hit and miss.

          • Mystery Man 0

            And PowerShell’s inventor left Microsoft. He’s working for Google now.

        • Blubberich 1

          Well it’s supposed to be the cross-platform PowerShell and framework.
          So what do you do about platform-specific stuff?

          Throw it out as happened here?
          Keep it in and require runtime checks for the platform?

          I see no way Microsoft can win here.

          • Mystery Man 1

            PowerShell 7.0, which was also cross-platform, could do it. C#, which is also cross-platform, can do it right now.

            And most importantly, this Windows Runtime nonsense that nobody seems to understand is a trap of Microsoft’s making. It shows no teamwork spirit towards anything except Microsoft Store apps, which are hard to develop, impossible to optimize, slow as tar, and incredibly hideous. Microsoft had 11 years to dismantle this nonsense. Except, the company kept digging itself into a hole.

      • George Tokmaji 0

        Windows PowerShell (aka PowerShell 5) is based on .NET Framework, PowerShell 7 on .NET Core.

          • Kalle Niemitalo 0

            The file is “C:\WINDOWS\system32\WinMetadata\Windows.ApplicationModel.winmd” but neither Windows PowerShell 5.1 nor PowerShell 7.3.3 can load it by calling Add-Type -AssemblyName, [System.Reflection.Assembly]::LoadFile, or [System.Reflection.Assembly]::LoadFrom.

            WinRT interop was removed in .NET 5. PowerShell 7.0.13 uses .NET Core 3.1.30 and seems to be the last release in which WinRT types can be natively referenced.

Feedback usabilla icon