Creating a PowerShell Binary Module
Tags: dotnet, powershell, module, dependency
Published: 2019-05-25 09:14:40

---
title: Creating a PowerShell Binary Module
published: true
description: Creating a Powershell Binary Module with dependencies
tags: dotnet, powershell, module, dependency
---
# Creating a PowerShell Binary Module

PowerShell is a fantastic tool for any computer user to get to grips with, and writing your own module is a great way to improve your productivity with commands you run regularly. I'm going to run through how to create a new binary module and how to include nuget package dependencies so that the module can be used.

## Prerequisites

I'm going to assume you're comfortable programming in C# and have a working knowledge of PowerShell, i.e. you are comfortable navigating to specific directories and running commands/scripts.

You'll need the (dotnet core SDK)[https://dotnet.microsoft.com/download], at least version 2.1.x, installed. I'm going to be using VSCode for the development work, but any text editor should suffice.

## Creating the project

In PowerShell navigate to where you want to keep your project. Mine is `C:\Projects\` and I'll create a PowerShell directory with the name of my module. In this case "Wozzo.SamplePsModule".

![Create and enter PowerShell Directory](https://thepracticaldev.s3.amazonaws.com/i/r0p20xu16sm5onubyhx6.png)

Now we're going to use the `dotnet` cli to install a template for the PowerShell module and then create a project from that template

```PowerShell
dotnet new install Microsoft.PowerShell.Standard.Module.Template
dotnet new psmodule
```

This will have created a new project with a sample Cmdlet which is ready to run. To import this module and run it use the following commands. 
Tip: I recommend doing this in a separate powershell window that you can close and reload since whenever you import the module the session will lock the dll file and you'll be unable to build again until it has been closed.

```PowerShell
dotnet build
Import-Module ".\bin\Debug\netstandard2.0\Wozzo.SamplePsModule.dll"
Test-SampleCmdlet 7 "Cat"
```
This should give the following output
```PowerShell
PS C:\Projects\Wozzo.SamplePsModule> Test-SampleCmdlet 7 "Cat"

FavoriteNumber FavoritePet
-------------- -----------
             7 Cat


PS C:\Projects\Wozzo.SamplePsModule>
```

The `TestSampleCmdletCommand.cs` file contains the code for this Cmdlet. The class must inherit from `System.Management.Automation.PsCmdlet`, and then uses several attributes to control how powershell describes the command and for parameters.

| Attribute  | Description                                                                                                                                                                                                                                                   | Example                                                                                                         |
|------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|
| Cmdlet     | Used to give the Cmdlet it's name. Accepts a verb and noun part to build the command name e.g Get-Location uses the verb 'Get' and the noun 'Location'. You should use the properties from the `Verbs...` classes provided by `System.Management.Automation`. | `[Cmdlet (VerbsCommon .Get ,"Location" )]`                                                                      |
| OutputType | Used to specify the expected output type from the Cmdlet                                                                                                                                                                                                      | `[OutputType(typeof(int))]`                                                                                     |
| Parameter  | Used to specify that a property is to be used to store the value of a parameter from the command line.                                                                                                                                                        | `[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]` |

There are other parameters, but these are the most common and required ones for building a basic cmdlet.

Note: Remember to build the project again you'll need to close the PowerShell window and open a new one to unlock the dll file.

## Adding a dependency

For any but the simplest of cmdlet's you're likely to want to use additional packages in your project. I'm going to create a Cmdlet which retrieves some json data from a http endpoint. To help me do this I'd like to use [Refit](https://github.com/reactiveui/refit), which is available as a nuget package, to create my client. Run the following command in the project root to add refit as a dependency.

```PowerShell
dotnet add package refit
```
Then create the following three items in new files in your project.

### Employee

This class will store the response from the API. Normally I'd tidy up the names, and use attributes to specify what json I'm expecting, but I'm trying to keep this simple.

```csharp
    public class Employee
    {
        public int id { get; set; }
        public string employee_name { get; set; }
        public int employee_salary { get; set; }
        public int employee_age { get; set; }
        public string profile_image { get; set; }
    }
```

### IPlaceholderApiClient

Not aiming to teach refit today, but check out the [refit readme](https://github.com/reactiveui/refit) on the project page for more details. Tldr; Just add methods to an interface to enable retrieving data from that endpoint.

```csharp
    public interface IPlaceholderApiClient {
        [Get("/api/v1/employees")]
        Task<IReadOnlyCollection<Employee>> GetEmployees();
    }
```

### The cmdlet

The cmdlet will use refit to create an instance of the client, then retrieve the result from the endpoint and then output it to the powershell pipeline.

```csharp
    [Cmdlet(VerbsCommon.Get, "Employees")]
    [OutputType(typeof(IReadOnlyCollection<Employee>))]
    public class GetEmployeesCmdlet : PSCmdlet
    {
        protected override void ProcessRecord()
        {
            var client = RestService.For<IPlaceholderApiClient>("http://placeholder.restapiexample.com");
            var employees = client.GetEmployees().Result;
            WriteObject(employees);
        }
    }
```

Note that the interface returns Tasks, and because PowerShell won't be too happy with us using async/await, we need to use the call to `.Result` to get the response from the endpoint.

### Running

Run the build command and try importing the module again. There should be no errors and the `Get-Employee` cmdlet should now be available. If we try to run it though...
```PowerShell
PS C:\Projects\Wozzo.SamplePsModule> Get-Employee 9004
Get-Employee : Could not load file or assembly 'Refit, Version=4.6.0.0, Culture=neutral, PublicKeyToken=null' or one of its
dependencies. The system cannot find the file specified.
At line:1 char:1
+ Get-Employee 9004
+ ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-Employee], FileNotFoundException
    + FullyQualifiedErrorId : System.IO.FileNotFoundException,Wozzo.SamplePsModule.GetEmployeeCmdlet

PS C:\Projects\Wozzo.SamplePsModule>
```
This is because our build isn't including the refit.dll and our module doesn't know it needs to be loaded when it is imported. We need to fix these things before we can proceed.

Edit the `.csproj` file and in the `<PropertyGroup>` section add the following
```xml
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
```
At this point when you build the dll's for the dependencies should now be included. If you try to run the command again the output should give a collection of employees
```powershell
PS C:\Projects\Wozzo.SamplePsModule> Get-Employees

id              : 10136
employee_name   : nick
employee_salary : 123
employee_age    : 23
profile_image   :

id              : 10137...
```

## Next steps

At this point your module is ready to be used. Next steps to get it production ready would be to [create a module manifest](https://learn.microsoft.com/en-us/powershell/scripting/developer/module/how-to-write-a-powershell-module-manifest). After that you could consider [publishing it on the PSGallery](https://docs.microsoft.com/en-us/powershell/gallery/how-to/publishing-packages/publishing-a-package). Happy PoShing