Don't waste your time with ($PSEdition -eq 'Core') in your PowerShell module manifest/psd1

I cannot believe my eyes.

I imagine some PowerShellers will disagree with me but when developing modules that support older versions of PowerShell, I refuse to even try to support Core vs Desktop in my module manifest. I imagine this will be the case for the next decade or two.

I've been working on dbatools 2.0 for a super long time. Like 6 months now, which I accept because life happens. I just got a new job and have a new commute and gotta settle in. I also have another project I'm working on that takes up my dbatools time.

Anyway, one of our biggest problems with dbatools pre-v2 was the SMO library. I love DLL-based API management but DLL/nuget library management is an incredible challenge in PowerShell because you have to do it all yourself. C# and dotnet will handle all that for you, but PS does not. This can easily lead to version requirement mismatches, especially for someone (me) that just isn't skilled in the way DLLs work.

I mean, look at the wild stuff I had to do to get bindingRedirect to work so that different versions of libraries with different required versions of other libraries would play nicely.

NEVERTHELESS! I decided I'd do things the right way. It started with a suggestion from the brilliant Kevin Marquette who said that he often splits out his large libraries like nuget packages into library modules. That way, people don't have to download the DLLs over and over and over again.

Sometimes, we'll update dbatools multiple times per day, but most often per week, and that can lead to a ton of space usage. Separating the library will save at least 100 MB per update.

Sounds good. What's the problem?

The problems come in when you want to deliver one library for .NET Core and another library/module for .NET Desktop (aka full aka classic aka standard).

Supporting .NET Core adds support for Linux, mac OS and PowerShell 7 on Windows. Incredible! 90's me probably couldn't comprehend this. So how is this done in the module manifest?

 1 RequiredModules        = @( 
 2     if ($PSEdition -eq 'Core') { 
 3         @( 
 4             @{ ModuleName = 'dbatools.core.library' } 
 5         ) 
 6     } else { 
 7         @( 
 8             @{ ModuleName = 'dbatools.library' } 
 9         ) 
10     } 
11 ) 

Easy enough! Well, not exactly. PowerShell v3 and v4 do not support this syntax but dbatools aims to support these older versions, so I had to create another module called dbatools.legacy, which was exactly the same, but used the old syntax in dbatools.psd1. Kinda funky, makes our book pretty inaccurate, but the huge upsides made it acceptable (don't look for it, it doesn't exist anymore).

Fellow maintainer, Shawn, hated it. I didn't love it, but.. it works?


The upsides were limited in number but HUGE in impact

  1. Size. 105MB for Core here, 51MB for Desktop there, no problem. This reduced size allows us to include the full-on versions of things like DacFx, SqlClient and XESmartTarget.
  2. Proper loading. Microsoft dotnet loves when your Nuget libraries are all in one big folder because it doesn't have to go looking in the GAC for other versions. When you don't have to worry about space usage, you can do things the right way/the way dotnet works best.

So what happened?

I got all of this working. I worked within my limitations but thought it was an acceptable and modern implementation, all around. For months, I coded like mad to ensure dbatools works gloriously on Linux, mac OS and Windows Desktop AND Core. Admittedly, we had too many modules in the Gallery, but we're progressing, right?

  • dbatools
  • dbatools.library
  • dbatools.core.library
  • dbatools.legacy

Then Shawn created this discussion on GitHub. Initially, he requested fewer modules to lessen the maintenance overhead, but I was going to take care of that with some workflows, nbd.

BUT THEN, I published a preview of dbatools 2.0 to the PowerShell Gallery and the blood drained from my face when I tried to install it fresh on WSL. Wait, what? No way on earth does the PowerShell Module Manifest support RequiredModules = @( if ($PSEdition -eq 'Core') but PowerShellGet does not.

Can I really not install dbatools with the dbatools.core.library module automatically using Install-Module? Apparently not when some sort of prerelease is involved.

Simply gutting. I had to go undo everything in a rage. Admittedly, it wasn't too much work because of the creative way I ended up doing the import (in the library modules, I created a command called Get-DbatoolsLibraryPath that made things super easy). Still! All that work, right down the drain.

Support older modules and want to save yourself boatloads of time? Just skip on checking for ($PSEdition -eq 'Core') in your module manifest and include everything you need in a combined module.