Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Loading" of Windows Runtime assemblies fails in 7.1 Preview 4 #13042

Closed
wi-fr opened this issue Jun 27, 2020 · 33 comments
Closed

"Loading" of Windows Runtime assemblies fails in 7.1 Preview 4 #13042

wi-fr opened this issue Jun 27, 2020 · 33 comments
Labels
Committee-Reviewed PS-Committee has reviewed this and made a decision Documentation Needed in this repo Documentation is needed in this repo Issue-Question ideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a Resolution-By Design The reported behavior is by design. WG-Engine core PowerShell engine, interpreter, and runtime

Comments

@wi-fr
Copy link

wi-fr commented Jun 27, 2020

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

@wi-fr wi-fr added the Issue-Question ideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a label Jun 27, 2020
@SeeminglyScience
Copy link
Collaborator

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).

@Windos
Copy link
Contributor

Windos commented Jun 28, 2020

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.

@iSazonov
Copy link
Collaborator

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 iSazonov added the WG-Engine core PowerShell engine, interpreter, and runtime label Jun 29, 2020
@SeeminglyScience
Copy link
Collaborator

@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.

@iSazonov
Copy link
Collaborator

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.

@iSazonov
Copy link
Collaborator

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

@Windos
Copy link
Contributor

Windos commented Jun 30, 2020

@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.

@iSazonov
Copy link
Collaborator

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.

@wi-fr
Copy link
Author

wi-fr commented Jun 30, 2020

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.

@Windos
Copy link
Contributor

Windos commented Jul 1, 2020

Can confirm, expected exception when importing the module.

Exception on module import

@SteveL-MSFT
Copy link
Member

I'll bring this up with the .NET team

@AdamBraden
Copy link

AdamBraden commented Jul 1, 2020

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’re 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.

@richlander
Copy link

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)?

@vexx32
Copy link
Collaborator

vexx32 commented Jul 1, 2020

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.

@SteveL-MSFT
Copy link
Member

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.

@iSazonov
Copy link
Collaborator

iSazonov commented Jul 3, 2020

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.

@iSazonov iSazonov added the Documentation Needed in this repo Documentation is needed in this repo label Jul 3, 2020
@Windos
Copy link
Contributor

Windos commented Jul 5, 2020

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

@SteveL-MSFT SteveL-MSFT added the Review - Committee The PR/Issue needs a review from the PowerShell Committee label Jul 7, 2020
@SteveL-MSFT
Copy link
Member

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

@Windos
Copy link
Contributor

Windos commented Jul 8, 2020

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

@SteveL-MSFT
Copy link
Member

@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

@SteveL-MSFT
Copy link
Member

@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.

@SteveL-MSFT SteveL-MSFT added Committee-Reviewed PS-Committee has reviewed this and made a decision Resolution-By Design The reported behavior is by design. and removed Review - Committee The PR/Issue needs a review from the PowerShell Committee labels Jul 8, 2020
@joeyaiello
Copy link
Contributor

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.

@Windos
Copy link
Contributor

Windos commented Jul 8, 2020

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

@iSazonov
Copy link
Collaborator

iSazonov commented Jul 9, 2020

/cc @sdwheeler for reference.

@xdhmoore
Copy link

xdhmoore commented Mar 15, 2021

Based on this thread I've been able to successfully use some WinRT classes in PowerShell by importing the two dlls in this BurntToast folder, but I can't figure out how to get or build these dlls from the primary source. Are these on NuGet somewhere?

  • Microsoft.Windows.SDK.NET.dll
  • WinRT.Runtime.dll

I'm attempting to update this library: https://github.com/rkeithhill/PoshWinRT which is a C# wrapper that can be imported in PowerShell in order to use APIs that use Async file operations.

@Windos
Copy link
Contributor

Windos commented Mar 15, 2021

@xdhmoore: https://www.nuget.org/packages/Microsoft.Windows.SDK.NET.Ref/

The Windows SDK available as a targeting pack for .NET 5 applications.

@ghost
Copy link

ghost commented Jul 8, 2021

This issue has been marked as by-design and has not had any activity for 1 day. It has been closed for housekeeping purposes.

@ghost ghost closed this as completed Jul 8, 2021
xan105 added a commit to xan105/node-powertoast that referenced this issue Aug 11, 2021
Must load Types from Assemblies
See PowerShell/PowerShell#13042
@anonhostpi
Copy link

You can now fix this with the Import-Package module that I just published to PowerShell gallery.

Import-Package "microsoft.windows.sdk.net.ref"

It automatically installs (if not already installed) the Microsoft.Windows.SDK.NET.Ref package and imports the whole .nupkg into the PowerShell session.

Small warning though:

That Microsoft package does not make use of the NuGet "runtime" directory, so Import-Package will not know that this package is Windows-specific, and will try to import it, even if you are running it from PowerShell on Linux.

@pronichkin
Copy link

I am sorry, but can someone please explain to non-programmers how to take advantage of this fix (or some other workaround)? I do not know anything about assemblies, namespaces, runtimes, etc. In my heart, I'm a mere sysadmin writing my 10-20 lines scripts that sometimes need to tackle Windows APIs, and historically PowerShell has been exceptionally good in that.

E.g., considering the basic examples in the very first message in this thread (or slighly more complex code samples like this), what exactly needs to be changed so that they work in PS7? (And, preferably, still work in PS5.1).

And I apologize if this has been already documented. Unfortunately, Internet search for "winRT PowerShell" currently gives you this thread as the most relevant link and not some documentation page.

@iSazonov
Copy link
Collaborator

@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.

@sdwheeler Have we the docs or a doc issue?

@sdwheeler
Copy link
Collaborator

@sdwheeler Sean Wheeler FTE Have we the docs or a doc issue?

@iSazonov No we don't have docs or a docs issue. Please open a docs issue and provide the necessary information needed for the docs.

@iSazonov
Copy link
Collaborator

I created doc issue but don't have specific information for this documentation. I hope the participants in this discussion will post steps for using WinRT there.

@Xavron
Copy link

Xavron commented Apr 2, 2024

@pronichkin

You can actually just run whatever code on the older PowerShell by wrapping stuff with eg powershell { } and yes it works with this issue. Its that simple to run the script code in another installed powershell version. I have pwsh as newer PS and powershell as older one. One result can be a script stuck running and that just means the code needs adjustment.

As a simple example. You can open PowerShell and run any PS version by typing the name for it eg in PS 5.1.x I can type pwsh in my instance: > $one = pwsh { get-host } and get the version info from PS 7.4.x into $one. This works the same in a script. After pressing enter/return, then can type $one to print the info. Could even do something like $one = pwsh {(get-host).Version} then if ($one -match "7.4.1") { "true" } else { "false" }. All of that kicks back to the fact that you can open your code anywhere in script in any installed PS version older or newer and bring stuff back.

Might as well also add that you can check PS version or whatever else in the scripts and have the scripts interact with multiple PS versions (I added some version example above that could be the start of that. match would need to be changed to a better means of matching). Just search the internet how to do it. I'm sure there's multiple things as I can come up with 2 ways at least in my head.

If you have an error like in OP, and an older installed PS version where it works, then you can do this as long as there's an old enough installed PS version available. You just need to figure out where to wrap your scripts or code to work best.

To me that is simpler and better than doing anything above and I use it but it depends on your situation (and opinion).

I can't help you further on this. Just giving a hint of something possible that you can do and adding another possibility here to deal with the issue =)

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Committee-Reviewed PS-Committee has reviewed this and made a decision Documentation Needed in this repo Documentation is needed in this repo Issue-Question ideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a Resolution-By Design The reported behavior is by design. WG-Engine core PowerShell engine, interpreter, and runtime
Projects
None yet
Development

No branches or pull requests