Skip to content
This repository has been archived by the owner on Jun 14, 2024. It is now read-only.

Guidance on writing new PS cmdlets in .net #94

Open
a-teece opened this issue Oct 21, 2021 · 8 comments
Open

Guidance on writing new PS cmdlets in .net #94

a-teece opened this issue Oct 21, 2021 · 8 comments

Comments

@a-teece
Copy link

a-teece commented Oct 21, 2021

Is this project abandoned and if so what is the new approach to writing PowerShell cmdlets in .net, specifically .net 5.0 and above?

The last release was over a year ago and is marked as a preview!

@JustinGrote
Copy link

@a-teece
Not a maintainer on this project but what I can say is I continue to use the 5.1.0 just fine.

More and more you're going to run into problems building for WinPS, so these should be your targets for compatability:

netstandard2.0 - WinPS5.1 and above. May need to make separate net472 and netcore builds depending on what your cmdlets use, very common for instance if you want to use SecureString for instance.
netcoreapp3.1 - PS7+ (LTS)
net5.0 - PS7.1+
net6.0 - PS7.2+ (next LTS when it releases)

It's a tradeoff, if you don't need to do 5.1 compatibility your life will be infinitely easier, you can still add the 5.1 PowerShellStandard and set PrivateAssets to true and it will exclude those DLLs from your module so it's smaller and lighter.

@a-teece
Copy link
Author

a-teece commented Nov 17, 2021

@JustinGrote I am lucky in that I only need to target PS7+ and can pretty much dictate the version as we currently only use our own cmdlets internally.

However I wondered if (given my need to just target PS7+) I should be using a different NuGet package. I believe the Cmdlets in the PowerShell repository don't reference this package so where do they get their Cmdlet base class from and should I be using the same?

Having written that and searched a little more I can see they get their base from System.Management.Automation....

So do you think that if targeting PS7+ only this PSStandard package can be skipped and System.Management.Automation used instead. However System.Management.Automation has a LOT more dependencies that this NuGet package so it certainly bloats a small library of cmdlets

I really feel some official documentation / guidance on this would help people to write cmdlets.

@a-teece
Copy link
Author

a-teece commented Nov 17, 2021

@iSazonov I have seen that yes. My scenario is "Implementing a PowerShell binary module" and I do "seek to compile against references to PowerShell without publishing it in their build".

In "PowerShell NuGet packages at a glance" it doesn't say which NuGet package to use for this, but the PowerShellStandard.Library is the smallest. The SDK package talks about rehosting PowerShell which I don't need to do, and even System.Management.Automation talks about "minimal hosted implementations". Again as I am not hosting PowerShell these didn't seem appropriate either.

For PowerShellStandard.Library it says "PowerShell Standard is intended for writing PowerShell modules, or other code only intended to be run after loading it into a PowerShell process. " which is exactly what I need. That is my scenario, writing cmdlets. The fact that I don't need or care about targeting multiple PowerShell versions isn't really covered.

So if I only need to target PS 7 or above (any specific version is fine), I want to compile against .net 5 or 6, I have no need to host PowerShell but I want to produce a small package which NuGet Package can I use. It feels like none. All have drawbacks:
System.Management.Automation - Large with a big dependency chain
PowerShellStandard.Library - Small but old. Can it be used with .net 6. I don't want to be constrained by .net standard 2.0

@JustinGrote
Copy link

@a-teece I can say in my experience you can depend against PowershellStandard.Library 7-preview1 fine and mark "PrivateAssets" as true and it will "exclude" most redundancies for a .net6 or .net5 targeted module.

For a recent module I did (FSharp) I had to exclude a lot more, here's a good starting place.

<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <OutputType>Library</OutputType>
    <SatelliteResourceLanguages>en</SatelliteResourceLanguages>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <AssemblySearchPaths>$(MSBuildSDKsPath)\..\FSharp;$(AssemblySearchPaths);</AssemblySearchPaths>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="Library.fs" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="fsharp.compiler.service" Version="41.0.1"/>
    <Content Include="FSharp.psd1" CopyToPublishDirectory="Always" />
  </ItemGroup>
  <ItemGroup>
    <!-- These are provided by Powershell 7 and dont need to be included in the package -->
    <PackageReference Include="System.Management.Automation" Version="7.0.0-preview.1" PrivateAssets="All"/>
    <PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" ExcludeAssets="all"/>
    <PackageReference Include="System.Drawing.Common" Version="6.0.0" ExcludeAssets="all"/>
    <PackageReference Include="System.Resources.Extensions" Version="6.0.0" ExcludeAssets="all"/>
    <PackageReference Include="System.Security.Cryptography.Pkcs" Version="6.0.0" ExcludeAssets="all"/>
    <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="6.0.0" ExcludeAssets="all"/>
    <PackageReference Include="System.Security.Cryptography.Xml" Version="6.0.0" ExcludeAssets="all"/>
    <PackageReference Include="System.Security.Permissions" Version="6.0.0" ExcludeAssets="all"/>
    <PackageReference Include="System.Windows.Extensions" Version="6.0.0" ExcludeAssets="all"/>
    <PackageReference Include="Microsoft.Win32.SystemEvents" Version="6.0.0" ExcludeAssets="all"/>
    <PackageReference Include="System.CodeDom" Version="6.0.0" ExcludeAssets="all"/>
  </ItemGroup>
</Project>

@a-teece
Copy link
Author

a-teece commented Nov 17, 2021

@JustinGrote Thanks for the tip. Basically keep using it, change the target framework and then mark this as private so it doesn't actually ship. Appreciate your input and hints.

Be great if something more formal could be done by the team.....

@iSazonov
Copy link

@a-teece You can see examples in https://github.com/PowerShell/modules

@JustinGrote
Copy link

JustinGrote commented Nov 29, 2021

@SteveL-MSFT @JamesWTruher I think @a-teece has a reasonable ask, seems like the README should be updated to:

  1. If you need to make a module that is 5.1+ compatible, reference PowershellStandard 5.1.0
  2. If you need to make a module that only has to be 7+ compatible, simply reference SMA and related dependencies and use PrivateAssets/ExcludeAssets to separate them.

For item 2 I feel like there should be a new "meta" nuget package that has all the PWSH assemblies that ship with pwsh, so that it can all be excluded via Private/ExcludeAssets in one go.

What is the deal with 7.0.0-preview? What in the API surface has to change to remain 5.1 compatible or is the 5.1.0 PowershellStandard still fine?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants