Powershell: "Loading" of Windows Runtime assemblies fails in 7.1 Preview 4

Created on 27 Jun 2020  路  24Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

[void][Windows.Storage.StorageFile, Windows.Storage, ContentType=WindowsRuntime]

[void][Windows.Graphics.Imaging.BitmapDecoder, Windows.Graphics, ContentType=WindowsRuntime]

Expected behavior

WinRT assemblies are loaded.

Actual behavior

InvalidOperation: Unable to find type [Windows.Storage.StorageFile,Windows.Storage, ContentType=WindowsRuntime].

InvalidOperation: Unable to find type [Windows.Graphics.Imaging.BitmapDecoder,Windows.Graphics, ContentType=WindowsRuntime].

Environment data

PSVersion 7.1.0-preview.4
PSEdition Core
GitCommitId 7.1.0-preview.4
OS Microsoft Windows 10.0.18363
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0鈥
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0

Committee-Reviewed Documentation Needed Issue-Question Resolution-By Design WG-Engine

Most helpful comment

I'll bring this up with the .NET team

All 24 comments

This is due to removal of builtin support in dotnet, see dotnet/runtime#37672.

/cc @SteveL-MSFT while this breaking change isn't PowerShell's fault, it will have a decent impact. It may be a good idea to look into adding built in support. C#/WinRT package seems to be the recommendation, though at a glance it doesn't look like that can be used as a general solution.

There are some very popular modules that utilize winrt APIs (like BurntToast by @Windos).

It may be that my morning coffee is only half drunk atm, but I'm struggling to wrap my head around making use of C#/WinRT in (non-C#) PowerShell.

From what I can see on the Gallery, the biggest use case of these WinRT assemblies are Toast Notifications of various flavours (Even dbatools uses them).

If we could wrangle built-in support in PowerShell that'd be super 馃挏. If not, it looks like module authors will need to figure out runtime projection... in BurntToast's case that'll probably mean a version or two that caps its host support at 7.0 until I/someone figure it out.

PowerShell has never WinRT support. The fact that users could load WinRT assemblies previously does not mean that everything worked out of the box. Moreover, the engine explicitly blocks WinRT event processing (Also it seems the engine consider WinRT types as special case).
To restore previous behavior users have to explicitly install C#/WinRT package (it seems it is still not ready for general use).
Since no changes was made in PowerShell engine all modules used WinRT directly (by p/invoke) should continue to work.

@iSazonov I 100% agree that this break isn't PowerShell's fault or even necessarily it's responsibility to fix. It still might be a good idea though.

PowerShell has never WinRT support.

In the same way it never supported System.Text.StringBuilder I suppose but if that disappeared tomorrow it might be a good idea to add it back.

Moreover, the engine explicitly blocks WinRT event processing (Also it seems the engine consider WinRT types as special case).

It also blocks processing of event handlers with a return type other than void. I'm guessing there are similar technical and/or design reasons.

In the same way it never supported System.Text.StringBuilder I suppose but if that disappeared tomorrow it might be a good idea to add it back.

Technically we would need to reference C # / WinRT package. But now the package is not ready for release. Also I guess MSFT team prefer to reduce PowerShell distributive size.

@Windos If I understand correctly BurntToast doesn't work on latest PowerShell preview. Do you consider C # / WinRT package for BurntToast?

@iSazonov Yeah, BurntToast 100% relies on WinRT assemblies so this change in .NET will break the module in PS preview. I missed Preview 4 before the MSI got pulled, so will confirm this when Preview 5 is out.

I will be looking into C#/WinRT, but haven't had a chance to sit down and figure that out yet.

I missed Preview 4 before the MSI got pulled, so will confirm this when Preview 5 is out.

@Windos You can load a nightly build from main page of the repo.

Another use case of WinRT assemblies that's worth to be considered are its bitmap decoders that support Apple's HEIF format. I'm not aware of any alternative provided by Microsoft.

Can confirm, expected exception when importing the module.

Exception on module import

I'll bring this up with the .NET team

With the breaking change in .NET5 Preview 6, https://devblogs.microsoft.com/dotnet/announcing-net-5-0-preview-6/, you will now need to reference a cswinrt generated interop assembly to call winrt apis. For the Windows WinRT apis, we've built a nuget package that provides this support, and will need to be referenced when building the module - https://www.nuget.org/packages/Microsoft.Windows.SDK.NET

.NET Blog
Today, we鈥檙e releasing .NET 5.0 Preview 6. It contains a small set of new features and performance improvements. The .NET 5.0 Preview 4 post covers what we are planning to deliver with .NET 5.0. Most of the features are now in the product,
The Windows SDK available as a NuGet package for more seamless acquisition and CI/CD integration. This package is designed for .NET 5 applications.

There are three big questions we need to answer:

  • Does referencing the package resolve this issue?
  • Does referencing the package / adding a dependency fit into a natural PS workflow?
  • What should we do to enable a PS module to support both PS 7.0 and 7.1 (to accommodate this breaking change)?

Modules referencing a nuget dependency is a scenario that still does not work anything close to well and isn't a supported scenario for PowerShellGet as far as I'm aware. Not sure if that's planned to change for v3 of that module but it really should if it hasn't already.

Until that's working _seamlessly_ things like this will need to be included in PowerShell itself to avoid breaking changes.

Workaround:

  1. include winrt.runtime.dll from microsoft.windows.cswinrt nupkg
  2. include Microsoft.Windows.SDK.NET.dll microsoft.windows.sdk.net nupkg

Add-Type -AssemblyName

In BurntToast, remove lines like 2137 that try to load the types using fully qualified names as those types are projected from different assemblies.

Was able to get New-BurntToastNotification to work.

I'd like to get PowerShellGetv3 to manage nuget.org dependencies but until that exists you'll have to pkg your module with those assemblies and load them.

I see a size of latest version of microsoft.windows.cswinrt package is ~977 Kb. We could add it in PowerShell 7.1 distribution until PowerShellGet addresses dependencies.

That was unbelievably easy, thanks for spelling out the work around @SteveL-MSFT!

Also, this whole thing also addresses #2181 as the reflection includes event handling and... that works now:

Working events

happy dance

_n.b. that last statement applies only to 7.1_

Will have PS-Committee review whether we should just include the necessary assemblies with PS7.1

Is that a community call review (and does that mean I'll have to wake up for the next call 馃槀)?

@Windos no, the PS-Committee is separate from the Monthly Community Calls. PS-Committee meets twice a week to weigh in on certain decisions affecting PowerShell

@PowerShell/powershell-committee reviewed this, we agreed that we will not be redistributing the WinRT assemblies with PowerShell 7.1. We also agreed to have documentation added to help PowerShell users that want to use WinRT.

More generally, we also agreed that we should, as a rule, snap to .NET's decision on API surface area except where there is overwhelming evidence that something has additional value to PS users. E.g. WinForms/WPF are used heavily in the PS ecosystem, and make sense to continue including on Windows.

Thanks for the quick decision on this. Will work on a module update to include the assemblies.

/cc @sdwheeler for reference.

Was this page helpful?
0 / 5 - 0 ratings