I wrote countless scripts and a good amount of modules (and functions) in my years as Service Engineer but all of them are script modules, I never really created binary modules. The main reason is that I like to write in Powershell but I also like the fact that, not being a compiled language, it is very easy to share and modify the source code for a script module and it is immediately ready to be reloaded and used. Anyway out of curiosity and to learn a different approach to building modules, I decided to try to convert one of mine from script to binary; my first step was (of course) a quick search to find some samples and getting started articles and I found a few good ones (referenced below) but all of them use Visual Studio and the full version of the .NET Framework, while I want to use Visual Studio Code and .NET Core. So here’s what I came up with.
First off of course I need .NET Core (I am using the latest .NET Core 3 preview 8 at the moment), Visual Studio Code and the C# Extension. Next, I’m going to create a Class Library project using dotnet
at the command line; note the -f
parameter to indicate the framework version I want to use:
PS > dotnet new classlib -f netcoreapp3.0 -o HelloWorldCore Couldn't find an installed template that matches the input, searching online for one that does... Matches from template source: NuGet ----------------------------------- Template name "Razor Class Library" (razorclasslib) from author "Microsoft" in pack Microsoft.DotNet.Web.ProjectTemplates.2.2 To use this template, run the following command and try again: dotnet new -i Microsoft.DotNet.Web.ProjectTemplates.2.2::2.2.6
Since I am attempting this command on a fresh installation I am missing some templates but luckily dotnet
suggests the command to run to fix this problem:
PS > dotnet new -i Microsoft.DotNet.Web.ProjectTemplates.2.2::2.2.6 Restore completed in 1.73 sec for C:\Users\carlo\.templateengine\dotnetcli\v3.0.100-preview8-013656\scratch\restore.csproj. Usage: new [options] Options: -h, --help Displays help for this command. -l, --list Lists templates containing the specified name. If no name is specified, lists all templates. -n, --name The name for the output being created. If no name is specified, the name of the current directory is used. -o, --output Location to place the generated output. -i, --install Installs a source or a template pack. -u, --uninstall Uninstalls a source or a template pack. --nuget-source Specifies a NuGet source to use during install. --type Filters templates based on available types. Predefined values are "project", "item" or "other". --dry-run Displays a summary of what would happen if the given command line were run if it would result in a template creation. --force Forces content to be generated even if it would change existing files. -lang, --language Filters templates based on language and specifies the language of the template to create. --update-check Check the currently installed template packs for updates. --update-apply Check the currently installed template packs for update, and install the updates. Templates Short Name Language Tags ---------------------------------------------------------------------------------------------------------------------------------- Console Application console [C#], F#, VB Common/Console Class library classlib [C#], F#, VB Common/Library WPF Application wpf [C#], VB Common/WPF WPF Class library wpflib [C#], VB Common/WPF WPF Custom Control Library wpfcustomcontrollib [C#], VB Common/WPF WPF User Control Library wpfusercontrollib [C#], VB Common/WPF Windows Forms (WinForms) Application winforms [C#], VB Common/WinForms Windows Forms (WinForms) Class library winformslib [C#], VB Common/WinForms Worker Service worker [C#] Common/Worker/Web Unit Test Project mstest [C#], F#, VB Test/MSTest NUnit 3 Test Project nunit [C#], F#, VB Test/NUnit NUnit 3 Test Item nunit-test [C#], F#, VB Test/NUnit xUnit Test Project xunit [C#], F#, VB Test/xUnit Razor Component razorcomponent [C#] Web/ASP.NET Razor Page page [C#] Web/ASP.NET MVC ViewImports viewimports [C#] Web/ASP.NET MVC ViewStart viewstart [C#] Web/ASP.NET Blazor Server App blazorserver [C#] Web/Blazor ASP.NET Core Empty web [C#], F# Web/Empty ASP.NET Core Web App (Model-View-Controller) mvc [C#], F# Web/MVC ASP.NET Core Web App webapp [C#] Web/MVC/Razor Pages ASP.NET Core with Angular angular [C#] Web/MVC/SPA ASP.NET Core with React.js react [C#] Web/MVC/SPA ASP.NET Core with React.js and Redux reactredux [C#] Web/MVC/SPA Razor Class Library razorclasslib [C#] Web/Razor/Library/Razor Class Library ASP.NET Core Web API webapi [C#], F# Web/WebAPI ASP.NET Core gRPC Service grpc [C#] Web/gRPC dotnet gitignore file gitignore Config global.json file globaljson Config NuGet Config nugetconfig Config Dotnet local tool manifest file tool-manifest Config Web Config webconfig Config Solution File sln Solution Protocol Buffer File proto Web/gRPC Examples: dotnet new mvc --auth Individual dotnet new nunit-test dotnet new --help
Now I can re-run the dotnet new
command:
PS > dotnet new classlib -f netcoreapp3.0 -o HelloWorldCore The template "Class library" was created successfully. Processing post-creation actions... Running 'dotnet restore' on HelloWorldCore\HelloWorldCore.csproj... Restore completed in 70.99 ms for C:\Users\carlo\Git\HelloWorldCore\HelloWorldCore.csproj. Restore succeeded. PS > Get-ChildItem -Recurse Directory: C:\Users\carlo\Git\HelloWorldCore Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 8/19/2019 4:59 PM bin d---- 8/19/2019 4:59 PM obj -a--- 8/19/2019 4:44 PM 91 Class1.cs -a--- 8/19/2019 4:44 PM 144 HelloWorldCore.csproj Directory: C:\Users\carlo\Git\HelloWorldCore\bin Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 8/19/2019 4:59 PM Debug Directory: C:\Users\carlo\Git\HelloWorldCore\bin\Debug Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 8/19/2019 4:59 PM netcoreapp3.0 Directory: C:\Users\carlo\Git\HelloWorldCore\obj Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 8/19/2019 4:59 PM Debug -a--- 8/19/2019 4:44 PM 149 HelloWorldCore.csproj.nuget.cache -a--- 8/19/2019 4:44 PM 2253 HelloWorldCore.csproj.nuget.dgspec.json -a--- 8/19/2019 4:44 PM 1166 HelloWorldCore.csproj.nuget.g.props -a--- 8/19/2019 4:44 PM 294 HelloWorldCore.csproj.nuget.g.targets -a--- 8/19/2019 4:44 PM 2268 project.assets.json Directory: C:\Users\carlo\Git\HelloWorldCore\obj\Debug Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 8/19/2019 4:59 PM netcoreapp3.0 Directory: C:\Users\carlo\Git\HelloWorldCore\obj\Debug\netcoreapp3.0 Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 8/19/2019 4:59 PM 1015 HelloWorldCore.AssemblyInfo.cs -a--- 8/19/2019 4:59 PM 42 HelloWorldCore.AssemblyInfoInputs.cache -a--- 8/19/2019 4:59 PM 188 HelloWorldCore.assets.cache -a--- 8/19/2019 4:59 PM 42 HelloWorldCore.csproj.CoreCompileInputs.cache -a--- 8/19/2019 4:59 PM 109810 HelloWorldCore.csprojAssemblyReference.cache
Even with .NET Core I still need to add a reference to the System.Management.Automation
assembly, which is available as a nuget
package. Visual Studio Code has a thriving marketplace with tons of very useful extension so I decided to check if something was available to help with this scenario and sure enough I found a number of suitable extensions. I went for NuGet Package Manager and I added a reference to System.Management.Automation
version 6.2.2 to match my .NET Core version
Now I can import the System.Management.Automation
namespace, decorate the class with the Cmdlet
attribute, have it inherit from Cmdlet
and override the ProcessRecord()
method; for this sample I don’t need to be too fancy with my code so here it is:
using System.Management.Automation; namespace HelloWorldCore { [Cmdlet(VerbsCommon.Get, "HelloWorld")] public class Class1 : Cmdlet { private string _name; [Parameter(Mandatory = true)] public string Name { get { return _name; } set { _name = value; } } protected override void ProcessRecord() { WriteObject("Hey " + this.Name); } } }
Next step, build the project and generate the .dll I will later import in my Powershell session; to do that I could use dotnet
at the command line or use a VSCode extension such as Dotnet core commands
PS > dotnet build --configuration Debug Microsoft (R) Build Engine version 16.3.0-preview-19377-01+dd8019d9e for .NET Core Copyright (C) Microsoft Corporation. All rights reserved. Restore completed in 1.63 sec for C:\Users\carlo\Git\HelloWorldCore\HelloWorldCore.csproj. You are using a preview version of .NET Core. See: https://aka.ms/dotnet-core-preview HelloWorldCore -> C:\Users\carlo\Git\HelloWorldCore\bin\Debug\netcoreapp3.0\HelloWorldCore.dll Build succeeded. 0 Warning(s) 0 Error(s) Time Elapsed 00:00:02.76
Finally, these are a few pointers to get started building binary Powershell modules
- Tutorials for Writing Cmdlets
- Examples of Cmdlets Code
- Using C# to Create PowerShell Cmdlets: The Basics
- Writing a PowerShell module in C#
You cannot help men permanently by doing for them what they could and should do for themselves. – Abraham Lincoln |