How To Debug PowerShell Core Binary Cmdlets

It's not exactly like it used to be

[3 minute read]

The Old Way

By definition, creating a PowerShell binary cmdlet library means the resulting file is a dll - not an exe - and therefore cannot be executed directly. Instead, it must be imported into and subsequently executed by PowerShell. Debugging a cmdlet library basically involves the same process: Instead of running the application directly, you tell Visual Studio to run PowerShell.exe, import your dll, and then you can commence debugging.

net classic settings

The New Way

For months I’ve been watching the development of the new PowerShell Standard Library nuget package because I wanted to start creating cross-platform cmdlet libraries. Six preview versions have been released since August of 2017, but the first RC just came out 10 days ago. Somewhere in there I gave one of the previews a shot and ran into some unexpected problems. At the time, I wasn’t particularly interested in wading through an early adopter jungle, so I set it aside until the package was closer to the finish line. Now that an RC is out, I decided to give it another shot. One again, I ran into an issue, but this time I realllllly wanted to figure it out.

You can read my StackOverflow question for more details, but in a nutshell I set up my PowerShell Core solution just like I would a PowerShell “Classic” solution, as described above, with a few obvious substitutions. Instead of targeting the .NET Framework 4.7, I targeted .NET Standard 2.0. Instead of using the PowerShell.5.ReferenceAssemblies package, I used the PowerShell Standard Library package. Instead of running the library with powershell.exe, I used pwsh.exe. In every other respect, the setup was the same. However, when I ran it, I got a FileNotFoundException on a nuget package reference.

Before I get to my solution, let me just say that I still don’t fully understand why this was happening. Yes, I consistently got a FileNotFoundException when referencing this SimpleInjector package. And yes, I did find a workaround for that problem. But I’m unable to explain why the same exception didn’t occur when referencing this package. Referencing worked perfectly fine. I know the problem isn’t specific to SimpleInjector because I was able to reproduce it with dummy “hello world” packages I created locally. Perhaps the explanation will become obvious over time as I work more with .NET Core and .NET Standard. For now, it remains a mystery.

Anyway, the solution is simple. First, create a post-build event that includes this statement: dotnet publish --no-build. Second, in the cmdlet project’s “Debug” properties, change the “Application arguments” such that the published dll is loaded into your PowerShell context. Using the example project I used in my Stackoverflow question, I changed this:

-NoExit -NoLogo -NoProfile -Command "Import-Module .\MyNetStandardProject.dll"

To this:

-NoExit -NoLogo -NoProfile -Command "Import-Module .\publish\MyNetStandardProject.dll"

Again, the only difference here is that I’m loading the published version of my dll. And with that, the FileNotFoundException disappeared.